欧美极品高清xxxxhd,国产日产欧美最新,无码AV国产东京热AV无码,国产精品人与动性XXX,国产传媒亚洲综合一区二区,四库影院永久国产精品,毛片免费免费高清视频,福利所导航夜趣136

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 410|回復: 6
打印 上一主題 下一主題
收起左側

求助:采用485采集風速和溫度只能采一樣

[復制鏈接]
回帖獎勵 5 黑幣 回復本帖可獲得 5 黑幣獎勵! 每人限 1 次
跳轉到指定樓層
樓主
本帖最后由 小橋流水不 于 2026-3-18 18:33 編輯

  使用stc15f2k48s2單片機,485接收溫濕度和風速,如果把Task1_Run里的//        if (currentTime - lastWindTime >= 1000)//        {
//            lastWindTime = currentTime;
//            ModbusMasterSendWindData();
//            windStep = 1;
//            windStartTime = currentTime;
//            printf("發送風速請求...\n");
//        }
    }屏蔽,能收到溫濕度數據,如果不屏蔽,只能收到風速和風力數據


這是代碼:

#include        "config.h"
#include        "timer.h"
#include        "USART.h"
#include        "delay.h"
#include "stdio.h"
#include        "GPIO.h"
#include "modbus_send_receive.h"
#include "modbus_crc.h"
#include "lcd12864.h"
#include "task_1.h"

/*************        功能說明        **************

雙串口全雙工中斷方式收發通訊程序。
串口1使用串口通訊,串口2使用RS485通訊

通過PC向MCU發送數據, MCU收到后通過串口把收到的數據通過原路返回.
兩個串口同時使用定時器2做為波特率發生器,兩個串口的波特率相同,如果需要不同波特率,
需改變串口1配置定時器,串口2固定使用定時器2做為波特率發生器
串口1波特率:9600
串口2波特率:9600


開機lcd12864第一行顯示“風速測量”
                        第二行顯示風速:和風速值
                        第三行顯示風力:和風力等級
                        
                        采用rs485和風速傳感器通訊,主機發送 01 03 00 00 00 02 C4 0B
            “01”代表儀表地址。修改此地址可以和不同地址的儀表通信。
                        “03”modbus.功能碼,使用03“0000” 儀表內部存器地址(即0x0000+0x01)
                        “0002”代表一次讀取2組數據
                        “C40B”CRC校驗,計算得到
                        此指令的意思是“用功能碼03讀取儀表地址為01的內部寄存器地址01(即0x00+0x01)開始的2個單位的數據”

           從機回復:01 03 04 00 02 00 01 9A 33
                   說明:
                        “01”代表儀表地址
                        “03”代表modbus功能碼
                        “04”代表后面4字節為對應儀表參數“0002”表示當前風速0x02=2,即0.02米/秒(默認2位小數點)
                        
                        收到回復后將數值解析顯示在LCD12864上,也通過串口1打印到pc上
                        
                        rs485采用串口2,波特率9600,串口發送接收控制引腳 :P12 在USART.h定義

******************************************/




xdata unsigned char str1[] = {"風速:"};
xdata unsigned char str2[] = {"風力:    級"};
xdata unsigned char str3[] = {"溫度:    "};
xdata unsigned char str4[] = {"℃"};
xdata unsigned char str5[] = {"濕度:"};
xdata unsigned char str6[] = {" %"};


void main(void)
{
        u8        i;

        Timer_config();
        UART_config();
        GPIO_config();
        Lcd12864_Init();
        EA = 1;

        Task1_Init();
        printf("Init is finish\n");
        while (1)
        {
               
               


                Task1_Run();
                delay_ms(1);
//                if(COM1.RX_TimeOut > 0)                //超時計數
//                {
//                        if(--COM1.RX_TimeOut == 0)
//                        {
//                                if(COM1.RX_Cnt > 0)
//                                {
//                                        for(i=0; i<COM1.RX_Cnt; i++)        
//                                        {
//                                                TX1_write2buff(RX1_Buffer);        //收到的數據通過串口1發送
//                                        }
//                                }
//                                COM1.RX_Cnt = 0;

//                        }
//                }

        }
}





#include "task_1.h"
#include "lcd12864.h"
#include "delay.h"
#include "modbus_send_receive.h"
#include "stdio.h"
#include "timer.h"
#include "USART.h"


/**
* @brief 風速顯示函數
*/
void WindSpeed_Display(u16 speed, u8 row, u8 position)
{

    xdata unsigned char digit[4] = {0};
    u8 lcd_row = row;

    // 邊界值處理:超過3690顯示無效
    if(speed > 3690)   
    {
        Lcd12864_SetPos(lcd_row, position);
        Lcd12864_WriteDat('-');
        Lcd12864_WriteDat('.');
        Lcd12864_WriteDat('-');
        Lcd12864_WriteDat('-');
        Lcd12864_WriteDat(' ');
                Lcd12864_WriteDat('m');
        Lcd12864_WriteDat('/');
        Lcd12864_WriteDat('s');
        return;
    }

    // 拆分四位數字(千/百/十/個)
    digit[0] = (speed / 1000) % 10;
    digit[1] = (speed / 100) % 10;
    digit[2] = (speed / 10) % 10;
    digit[3] = speed % 10;

    // 設置顯示位置
    Lcd12864_SetPos(lcd_row, position);

    // 顯示整數部分(處理前導0)
    if(digit[0] == 0 && digit[1] == 0)
    {
        Lcd12864_WriteDat('0');
    }
    else
    {
        if(digit[0] != 0)
        {
            Lcd12864_WriteDat(digit[0] + '0');
        }
        Lcd12864_WriteDat(digit[1] + '0');
    }

    // 小數點+小數部分
    Lcd12864_WriteDat('.');
    Lcd12864_WriteDat(digit[2] + '0');
    Lcd12864_WriteDat(digit[3] + '0');

    // 單位
    Lcd12864_WriteDat(' ');
        Lcd12864_WriteDat('m');
    Lcd12864_WriteDat('/');
    Lcd12864_WriteDat('s');
}

/**
* @brief 風級顯示函數
*/
void WindLevel_Display(u16 level, u8 row, u8 position)
{
    xdata unsigned char digit[2] = {0};
    u8 lcd_row = row;

    // 風級邊界處理(0~12級)
    if(level > 12)
    {
        Lcd12864_SetPos(lcd_row, position);
        Lcd12864_WriteDat('-');
        Lcd12864_WriteDat('-');

        return;
    }

    // 拆分風級數字
    digit[0] = (level / 10) % 10; // 十位
    digit[1] = level % 10;        // 個位

    Lcd12864_SetPos(lcd_row, position);

    // 顯示風級(處理前導0)
    if(digit[0] == 0)
    {
        Lcd12864_WriteDat(' '); // 十位為0時顯示空格
    }
    else
    {
        Lcd12864_WriteDat(digit[0] + '0');
    }
    Lcd12864_WriteDat(digit[1] + '0');

}

/**
* @brief 溫度顯示函數
*/
void Temperature_Display(int temp_value, u8 row, u8 position)
{
    u8 digit[3];
    u8 neg_flag = 0;

    if (temp_value < 0)
    {
        neg_flag = 1;
        temp_value = -temp_value;
    }

    digit[0] = (temp_value / 100) % 10;
    digit[1] = (temp_value / 10) % 10;
    digit[2] = temp_value % 10;

    Lcd12864_SetPos(row, position);

    if (neg_flag)
        Lcd12864_WriteDat('-');
    else
        Lcd12864_WriteDat(' ');

    if (digit[0] == 0)
        Lcd12864_WriteDat(' ');
    else
        Lcd12864_WriteDat(digit[0] + '0');

    Lcd12864_WriteDat(digit[1] + '0');
    Lcd12864_WriteDat('.');
    Lcd12864_WriteDat(digit[2] + '0');
}

/**
* @brief 濕度顯示函數
*/
void Humidity_Display(u16 humi_value, u8 row, u8 position)
{
    u8 digit[3];

    digit[0] = (humi_value / 100) % 10;
    digit[1] = (humi_value / 10) % 10;
    digit[2] = humi_value % 10;

    Lcd12864_SetPos(row, position);

    if (digit[0] == 0)
        Lcd12864_WriteDat(' ');
    else
        Lcd12864_WriteDat(digit[0] + '0');

    Lcd12864_WriteDat(digit[1] + '0');
    Lcd12864_WriteDat('.');
    Lcd12864_WriteDat(digit[2] + '0');
}

/**
* @brief 任務1初始化
*/
void Task1_Init(void)
{
    Lcd12864_WriteCmd(0x01); // 清屏
    delay_ms(20);

    // 顯示靜態文本
    Lcd12864_SetPos(1, 1); Lcd12864_WriteCN(str1);
    Lcd12864_SetPos(2, 1); Lcd12864_WriteCN(str2);

    Lcd12864_SetPos(3, 1); Lcd12864_WriteCN(str3);
    Lcd12864_SetPos(3, 7); Lcd12864_WriteCN(str4);  // "C"
    Lcd12864_SetPos(4, 1); Lcd12864_WriteCN(str5);
    Lcd12864_SetPos(4, 6); Lcd12864_WriteCN(str6);  // "%"

    // 初始顯示0值
    WindSpeed_Display(0, 1, 4);
    WindLevel_Display(0, 2, 4);
    Temperature_Display(0, 3, 4);
    Humidity_Display(0, 4, 4);

    Modbus_ClearBuffer();
    printf("Task1初始化完成\n");
}

/**
* @brief 任務1運行 - 修正版(雙獨立狀態機)
*/
void Task1_Run(void)
{
    static u32 lastWindTime = 0;
    static u32 lastTempTime = 0;
    static u16 lastWindSpeed = 0;
    static u16 lastWindLevel = 0;
    static int lastTemp = 0;
    static u16 lastHumi = 0;

    // 風速獨立狀態
    static u8 windStep = 0;  // 0:空閑, 1:等待響應
    static u32 windStartTime = 0;

    // 溫濕度獨立狀態
    static u8 tempStep = 0;  // 0:空閑, 1:等待響應
    static u32 tempStartTime = 0;

    u32 currentTime = GetSysTimeMs();
        
        

        

    // ========== 風速處理(獨立) ==========
    if (windStep == 0)
    {
        // 空閑狀態,檢查是否需要發送
        if (currentTime - lastWindTime >= 1000)
        {
            lastWindTime = currentTime;
            ModbusMasterSendWindData();
            windStep = 1;
            windStartTime = currentTime;
            printf("發送風速請求...\n");
        }
    }
    else if (windStep == 1)
    {
        // 等待風速響應
        ModbusMasterReceiveWind();

        // 超時處理(500ms)
        if (currentTime - windStartTime > 500)
        {
            printf("風速響應超時\n");
            windStep = 0;
            COM2.RX_Cnt = 0;
        }
        // 接收完成
        else if (COM2.RX_TimeOut == 0 && COM2.RX_Cnt == 0)
        {
            windStep = 0;
        }
    }

                // ========== 溫濕度處理(獨立) ==========
    if (tempStep == 0)
    {
        // 空閑狀態,檢查是否需要發送
        if (currentTime - lastTempTime >= 3000)
        {
            lastTempTime = currentTime;
            ModbusMasterSendTempHumiData();
            tempStep = 1;
            tempStartTime = currentTime;
            printf("發送溫濕度請求...\n");
        }
    }
    else if (tempStep == 1)
    {
        // 等待溫濕度響應
        ModbusMasterReceiveTempHumi();

        // 超時處理(500ms)
        if (currentTime - tempStartTime > 500)
        {
            printf("溫濕度響應超時\n");
            tempStep = 0;
            COM2.RX_Cnt = 0;
        }
        // 接收完成
        else if (COM2.RX_TimeOut == 0 && COM2.RX_Cnt == 0)
        {
            tempStep = 0;
        }
    }
        

    // 心跳燈
    if (currentTime % 500 < 50)
    {
        P00 = 0;
    }
    else
    {
        P00 = 1;
    }

    // 更新LCD顯示(僅在數據變化時)
    if (windSpeed != lastWindSpeed || windLevel != lastWindLevel)
    {
        WindSpeed_Display(windSpeed, 1, 4);
        WindLevel_Display(windLevel, 2, 4);
        printf("LCD更新 - 風速:%u(%.2f) 風級:%u\n",
               windSpeed, windSpeed*0.01f, windLevel);
        lastWindSpeed = windSpeed;
        lastWindLevel = windLevel;
    }

    if (temp != lastTemp || humi != lastHumi)
    {
        Temperature_Display(temp, 3, 4);
        Humidity_Display(humi, 4, 4);
        printf("LCD更新 - 溫度:%d.%d℃ 濕度:%u.%u%%\n",
               temp/10, (temp<0 ? -(temp%10) : temp%10),
               humi/10, humi%10);
        lastTemp = temp;
        lastHumi = humi;
    }
}







#ifndef __TASK_1_H
#define __TASK_1_H

#include "config.h"

// 字符串聲明
extern xdata unsigned char str1[];
extern xdata unsigned char str2[];
extern xdata unsigned char str3[];
extern xdata unsigned char str4[];
extern xdata unsigned char str5[];
extern xdata unsigned char str6[];

// 函數聲明
void Task1_Init(void);
void Task1_Run(void);
void WindSpeed_Display(u16 speed, u8 row, u8 position);
void WindLevel_Display(u16 level, u8 row, u8 position);
void Temperature_Display(int temp_value, u8 row, u8 position);
void Humidity_Display(u16 humi_value, u8 row, u8 position);

#endif







#include "string.h"
#include "modbus_send_receive.h"
#include "timer.h"
#include "stdio.h"
#include "delay.h"
#include "USART.h"
#include "modbus_crc.h"
#include "GPIO.h"

// 全局變量定義
u32 sendFreTime = 0;
u8 xdata sendBuf[8] = {0};
u8 xdata receiveBuf[9] = {0};
u8 xdata temp_humi_buf[9] = {0};  // 溫濕度專用接收緩沖區
u16 windSpeed = 0;
u16 windLevel = 0;
int temp = 0;    // 溫度,有符號整數
u16 humi = 0;       // 濕度,無符號整數

/**
* @brief  清除接收緩沖區
*/
void Modbus_ClearBuffer(void)
{
    COM2.RX_Cnt = 0;
    COM2.RX_TimeOut = 0;
    memset(receiveBuf, 0, sizeof(receiveBuf));
    memset(temp_humi_buf, 0, sizeof(temp_humi_buf));
}

/**
* @brief  組裝風速讀取指令(地址0x01)
*/
void ModbusMasterSetWindCmd(void)
{
    u16 crc;

    sendBuf[0] = SLAVE_ADDR_WIND;        // 從機地址 0x01
    sendBuf[1] = FUNC_READ_HOLD_REGS;    // 功能碼 0x03
    sendBuf[2] = 0x00;                   // 寄存器起始地址高字節
    sendBuf[3] = REG_ADDR_START;         // 寄存器起始地址低字節 0x00
    sendBuf[4] = 0x00;                   // 寄存器數量高字節
    sendBuf[5] = REG_COUNT_READ;         // 寄存器數量低字節 0x02

    crc = ModbusCRC16(sendBuf, 6);
    sendBuf[6] = (u8)(crc & 0xFF);       // CRC低字節
    sendBuf[7] = (u8)(crc >> 8);         // CRC高字節
}

/**
* @brief  發送風速讀取指令
*/
void ModbusMasterSendWindData(void)
{
    u8 i = 0;

    ModbusMasterSetWindCmd();

    printf("\n發送風速指令: ");
    for (i = 0; i < 8; i++)
    {
        TX2_write2buff(sendBuf);
        printf("%bx ", sendBuf);
    }
    printf("\n");
}

/**
* @brief  接收并解析風速/風級
*/
void ModbusMasterReceiveWind(void)
{
    u16 crc_calc;
    u8 len;
    u8 i;

    if (COM2.RX_TimeOut == 0)
    {
        printf("風速超時,無數據\n");
        return;
    }

    if (--COM2.RX_TimeOut == 0)
    {
        if (COM2.RX_Cnt > 0)
        {
            len = COM2.RX_Cnt;

            printf("風速原始數據(%d): ", len);
            for(i=0; i<len; i++)
            {
                printf("%bx ", RX2_Buffer);
            }
            printf("\n");

            // 檢查長度
            if (len != 9)
            {
                printf("風速長度錯誤: %d, 期望9\n", len);
                COM2.RX_Cnt = 0;
                return;
            }

            // 復制數據
            for(i=0; i<9; i++) receiveBuf = RX2_Buffer;

            // 打印解析的數據
            printf("解析: 地址=%bx, 功能碼=%bx, 長度=%bx, ",
                   receiveBuf[0], receiveBuf[1], receiveBuf[2]);
            printf("數據=%bx%bx %bx%bx, CRC=%bx%bx\n",
                   receiveBuf[3], receiveBuf[4], receiveBuf[5], receiveBuf[6],
                   receiveBuf[7], receiveBuf[8]);

            // 地址校驗
            if(receiveBuf[0] != SLAVE_ADDR_WIND)
            {
                printf("風速地址錯誤: 期望%bx, 收到%bx\n",
                       SLAVE_ADDR_WIND, receiveBuf[0]);
                COM2.RX_Cnt = 0;
                return;
            }

            // 功能碼校驗
            if(receiveBuf[1] != FUNC_READ_HOLD_REGS)
            {
                printf("風速功能碼錯誤\n");
                COM2.RX_Cnt = 0;
                return;
            }

            // CRC校驗
            crc_calc = ModbusCRC16(receiveBuf, 7);
            if(receiveBuf[7] == (u8)(crc_calc & 0xFF) &&
               receiveBuf[8] == (u8)(crc_calc >> 8))
            {
                windSpeed = (u16)receiveBuf[3] << 8 | receiveBuf[4];
                windLevel = (u16)receiveBuf[5] << 8 | receiveBuf[6];

                printf("風速解析成功: %u (%.2f m/s), 風級: %u\n",
                       windSpeed, windSpeed * 0.01f, windLevel);
            }
            else
            {
                printf("風速CRC錯誤: 計算=%u, 收到=%bx%bx\n",
                       crc_calc, receiveBuf[8], receiveBuf[7]);
            }

            COM2.RX_Cnt = 0;
        }
        else
        {
            printf("風速接收緩沖區為空\n");
        }
    }
}

/**
* @brief  組裝溫濕度讀取指令(地址0x02)
*/
void ModbusMasterSetTempHumiCmd(void)
{
    u16 crc;

    sendBuf[0] = SLAVE_ADDR_TEMP_HUMI;   // 從機地址 0x02
    sendBuf[1] = FUNC_READ_HOLD_REGS;    // 功能碼 0x03
    sendBuf[2] = 0x00;                   // 寄存器起始地址高字節
    sendBuf[3] = REG_ADDR_START;         // 寄存器起始地址低字節 0x00
    sendBuf[4] = 0x00;                   // 寄存器數量高字節
    sendBuf[5] = REG_COUNT_READ;         // 寄存器數量低字節 0x02

    crc = ModbusCRC16(sendBuf, 6);
    sendBuf[6] = (u8)(crc & 0xFF);       // CRC低字節
    sendBuf[7] = (u8)(crc >> 8);         // CRC高字節
}

/**
* @brief  發送溫濕度讀取指令
*/
void ModbusMasterSendTempHumiData(void)
{
    u8 i = 0;

    ModbusMasterSetTempHumiCmd();

    printf("\n發送溫濕度指令: ");
    for (i = 0; i < 8; i++)
    {
        TX2_write2buff(sendBuf);
        printf("%bX ", sendBuf);
    }
    printf("\n");
}

/**
* @brief  接收并解析溫濕度
*/
void ModbusMasterReceiveTempHumi(void)
{
    u16 crc_calc;
    u8 len;
        u8 i;
    u16 raw_temp;
        

    if (COM2.RX_TimeOut == 0) return;

    if (--COM2.RX_TimeOut == 0)
    {
        if (COM2.RX_Cnt > 0)
        {
            len = COM2.RX_Cnt;
            memcpy(temp_humi_buf, RX2_Buffer, len);

            printf("收到溫濕度數據(%d字節): ", len);
            for( i=0; i<len; i++) printf("%bX ", temp_humi_buf);
            printf("\n");

            // 校驗數據長度
            if (len != 9)
            {
                printf("溫濕度長度錯誤: %d, 期望9字節\n", len);
                COM2.RX_Cnt = 0;
                return;
            }

            // 地址和功能碼校驗
            if (temp_humi_buf[0] != SLAVE_ADDR_TEMP_HUMI ||
                temp_humi_buf[1] != FUNC_READ_HOLD_REGS)
            {
                printf("溫濕度地址/功能碼錯誤: Addr=0x%bX, Func=0x%bX\n",
                       temp_humi_buf[0], temp_humi_buf[1]);
                COM2.RX_Cnt = 0;
                return;
            }

            // 數據長度校驗
            if (temp_humi_buf[2] != 0x04)
            {
                printf("溫濕度數據長度錯誤: 0x%bX\n", temp_humi_buf[2]);
                COM2.RX_Cnt = 0;
                return;
            }

            // CRC校驗
            crc_calc = ModbusCRC16(temp_humi_buf, 7);
            if (temp_humi_buf[7] == (u8)(crc_calc & 0xFF) &&
                temp_humi_buf[8] == (u8)(crc_calc >> 8))
            {
                // 解析數據:前兩個字節是濕度,后兩個字節是溫度
                humi = (u16)temp_humi_buf[3] << 8 | temp_humi_buf[4];
                raw_temp = (u16)temp_humi_buf[5] << 8 | temp_humi_buf[6];

                // 溫度可能是帶符號的(如果傳感器支持負溫度)
                if (raw_temp > 0x7FFF)
                {
                    temp = (int)(raw_temp - 0x10000);
                }
                else
                {
                    temp = (int)raw_temp;
                }

                printf("溫濕度解析成功: 濕度=%u.%u%%, 溫度=%d.%d℃\n",
                       humi/10, humi%10,
                       temp/10, (temp < 0 ? -temp%10 : temp%10));
            }
            else
            {
                printf("溫濕度CRC錯誤! 計算: 0x%bX, 收到: 0x%bX%bX\n",
                       crc_calc, temp_humi_buf[8], temp_humi_buf[7]);
            }

            COM2.RX_Cnt = 0;
        }
    }
}





#ifndef        __MODBUS_SEND_RECEIVE_H
#define        __MODBUS_SEND_RECEIVE_H

#include        "config.h"

// 協議相關宏定義
#define SLAVE_ADDR_WIND         0x01    // 風速傳感器地址
#define SLAVE_ADDR_TEMP_HUMI    0x02    // 溫濕度傳感器地址
#define FUNC_READ_HOLD_REGS     0x03    // 讀保持寄存器功能碼
#define REG_ADDR_START          0x00    // 寄存器起始地址
#define REG_COUNT_READ          0x02    // 要讀取的寄存器數量

// ==================== 全局變量聲明 ====================
extern u32 sendFreTime;                     // 串口發送數據間隔
extern u8 xdata sendBuf[8];                 // 發送緩沖區
extern u8 xdata receiveBuf[9];              // 風速接收緩沖區
extern u8 xdata temp_humi_buf[9];           // 溫濕度接收緩沖區
extern u16 windSpeed;                       // 風速值 (單位: 0.01 m/s)
extern u16 windLevel;                       // 風級值
extern int temp;                      // 溫度值 (單位: 0.1℃)
extern u16 humi;                         // 濕度值 (單位: 0.1%)

// ==================== 函數聲明 ====================
/**
* @brief  組裝風速讀取指令
*/
void ModbusMasterSetWindCmd(void);

/**
* @brief  發送風速讀取指令
*/
void ModbusMasterSendWindData(void);

/**
* @brief  接收并解析風速/風級
*/
void ModbusMasterReceiveWind(void);

/**
* @brief  組裝溫濕度讀取指令
*/
void ModbusMasterSetTempHumiCmd(void);

/**
* @brief  發送溫濕度讀取指令
*/
void ModbusMasterSendTempHumiData(void);

/**
* @brief  接收并解析溫濕度
*/
void ModbusMasterReceiveTempHumi(void);

/**
* @brief  清除接收緩沖區
*/
void Modbus_ClearBuffer(void);

#endif








#include "USART.h"
#include "stdio.h"
#include        "delay.h"






COMx_Define        COM1,COM2;
u8        xdata TX1_Buffer[COM_TX1_Lenth];        //發送緩沖
u8         xdata RX1_Buffer[COM_RX1_Lenth];        //接收緩沖
u8        xdata TX2_Buffer[COM_TX2_Lenth];        //發送緩沖
u8         xdata RX2_Buffer[COM_RX2_Lenth];        //接收緩沖

u8 USART_Configuration(u8 UARTx, COMx_InitDefine *COMx)
{
        u8        i;
        u32        j;
        
        if(UARTx == USART1)
        {
                COM1.id = 1;
                COM1.TX_read    = 0;
                COM1.TX_write   = 0;
                COM1.B_TX_busy  = 0;
                COM1.RX_Cnt     = 0;
                COM1.RX_TimeOut = 0;
                COM1.B_RX_OK    = 0;
                for(i=0; i<COM_TX1_Lenth; i++)        TX1_Buffer = 0;
                for(i=0; i<COM_RX1_Lenth; i++)        RX1_Buffer = 0;

                if(COMx->UART_Mode > UART_9bit_BRTx)        return 2;        //模式錯誤
                if(COMx->UART_Polity == PolityHigh)                PS = 1;        //高優先級中斷
                else                                                                        PS = 0;        //低優先級中斷
                SCON = (SCON & 0x3f) | COMx->UART_Mode;
                if((COMx->UART_Mode == UART_9bit_BRTx) ||(COMx->UART_Mode == UART_8bit_BRTx))        //可變波特率
                {
                        j = (MAIN_Fosc / 4) / COMx->UART_BaudRate;        //按1T計算
                        if(j >= 65536UL)        return 2;        //錯誤
                        j = 65536UL - j;
                        if(COMx->UART_BRT_Use == BRT_Timer1)
                        {
                                TR1 = 0;
                                AUXR &= ~0x01;                //S1 BRT Use Timer1;
                                TMOD &= ~(1<<6);        //Timer1 set As Timer
                                TMOD &= ~0x30;                //Timer1_16bitAutoReload;
                                AUXR |=  (1<<6);        //Timer1 set as 1T mode
                                TH1 = (u8)(j>>8);
                                TL1 = (u8)j;
                                ET1 = 0;        //禁止中斷
                                TMOD &= ~0x40;        //定時
                                INT_CLKO &= ~0x02;        //不輸出時鐘
                                TR1  = 1;
                        }
                        else if(COMx->UART_BRT_Use == BRT_Timer2)
                        {
                                AUXR &= ~(1<<4);        //Timer stop
                                AUXR |= 0x01;                //S1 BRT Use Timer2;
                                AUXR &= ~(1<<3);        //Timer2 set As Timer
                                AUXR |=  (1<<2);        //Timer2 set as 1T mode
                                TH2 = (u8)(j>>8);
                                TL2 = (u8)j;
                                IE2  &= ~(1<<2);        //禁止中斷
                                AUXR &= ~(1<<3);        //定時
                                AUXR |=  (1<<4);        //Timer run enable
                        }
                        else return 2;        //錯誤
                }
                else if(COMx->UART_Mode == UART_ShiftRight)
                {
                        if(COMx->BaudRateDouble == ENABLE)        AUXR |=  (1<<5);        //固定波特率SysClk/2
                        else                                                                AUXR &= ~(1<<5);        //固定波特率SysClk/12
                }
                else if(COMx->UART_Mode == UART_9bit)        //固定波特率SysClk*2^SMOD/64
                {
                        if(COMx->BaudRateDouble == ENABLE)        PCON |=  (1<<7);        //固定波特率SysClk/32
                        else                                                                PCON &= ~(1<<7);        //固定波特率SysClk/64
                }
                if(COMx->UART_Interrupt == ENABLE)        ES = 1;        //允許中斷
                else                                                                ES = 0;        //禁止中斷
                if(COMx->UART_RxEnable == ENABLE)        REN = 1;        //允許接收
                else                                                                REN = 0;        //禁止接收
                P_SW1 = (P_SW1 & 0x3f) | (COMx->UART_P_SW & 0xc0);        //切換IO
                if(COMx->UART_RXD_TXD_Short == ENABLE)        PCON2 |=  (1<<4);        //內部短路RXD與TXD, 做中繼, ENABLE,DISABLE
                else                                                                        PCON2 &= ~(1<<4);
                return        0;
        }

        if(UARTx == USART2)
        {
                COM2.id = 2;
                COM2.TX_read    = 0;
                COM2.TX_write   = 0;
                COM2.B_TX_busy  = 0;
                COM2.RX_Cnt     = 0;
                COM2.RX_TimeOut = 0;
                COM2.B_RX_OK    = 0;
                for(i=0; i<COM_TX2_Lenth; i++)        TX2_Buffer = 0;
                for(i=0; i<COM_RX2_Lenth; i++)        RX2_Buffer = 0;

                if((COMx->UART_Mode == UART_9bit_BRTx) ||(COMx->UART_Mode == UART_8bit_BRTx))        //可變波特率
                {
                        if(COMx->UART_Polity == PolityHigh)                IP2 |=  1;        //高優先級中斷
                        else                                                                        IP2 &= ~1;        //低優先級中斷
                        if(COMx->UART_Mode == UART_9bit_BRTx)        S2CON |=  (1<<7);        //9bit
                        else                                                                        S2CON &= ~(1<<7);        //8bit
                        j = (MAIN_Fosc / 4) / COMx->UART_BaudRate;        //按1T計算
                        if(j >= 65536UL)        return 2;        //錯誤
                        j = 65536UL - j;
                        AUXR &= ~(1<<4);        //Timer stop
                        AUXR &= ~(1<<3);        //Timer2 set As Timer
                        AUXR |=  (1<<2);        //Timer2 set as 1T mode
                        TH2 = (u8)(j>>8);
                        TL2 = (u8)j;
                        IE2  &= ~(1<<2);        //禁止中斷
                        AUXR |=  (1<<4);        //Timer run enable
                }
                else        return 2;        //模式錯誤
                if(COMx->UART_Interrupt == ENABLE)        IE2   |=  1;                //允許中斷
                else                                                                IE2   &= ~1;                //禁止中斷
                if(COMx->UART_RxEnable == ENABLE)        S2CON |=  (1<<4);        //允許接收
                else                                                                S2CON &= ~(1<<4);        //禁止接收
                P_SW2 = (P_SW2 & ~1) | (COMx->UART_P_SW & 0x01);        //切換IO
        }
}


/*************** 裝載串口發送緩沖 *******************************/

void TX1_write2buff(u8 dat)        //寫入發送緩沖,指針+1
{
        TX1_Buffer[COM1.TX_write] = dat;        //裝發送緩沖
        if(++COM1.TX_write >= COM_TX1_Lenth)        COM1.TX_write = 0;

        if(COM1.B_TX_busy == 0)                //空閑
        {  
                COM1.B_TX_busy = 1;                //標志忙
                TI = 1;                                        //觸發發送中斷
        }
}

void TX2_write2buff(u8 dat)        //寫入發送緩沖,指針+1
{
    // 關鍵修改:只在發送第一個字節時切換485方向
    if (COM2.B_TX_busy == 0)  // 空閑狀態,即將開始發送
    {
        RS485_DIR_PIN = RS485_TX_MODE;  // 切到發送模式
        delay_us(200);  // 重要!延時等待485芯片切換完成(200微秒)
    }

    TX2_Buffer[COM2.TX_write] = dat;
    if(++COM2.TX_write >= COM_TX2_Lenth) COM2.TX_write = 0;

    if(COM2.B_TX_busy == 0)                //空閑
    {  
        COM2.B_TX_busy = 1;                //標志忙
        SET_TI2();                                //觸發發送中斷
    }
}


void PrintString1(u8 *puts)
{
    for (; *puts != 0;        puts++)  TX1_write2buff(*puts);         //遇到停止符0結束
}

void PrintString2(u8 *puts)
{
    for (; *puts != 0;        puts++)  TX2_write2buff(*puts);         //遇到停止符0結束
}

/*
void COMx_write2buff(COMx_Define *COMx, u8 dat)        //寫入發送緩沖,指針+1
{
        if(COMx->id == 1)        TX1_write2buff(dat);
        if(COMx->id == 2)        TX2_write2buff(dat);
}

void PrintString(COMx_Define *COMx, u8 *puts)
{
    for (; *puts != 0;        puts++)  COMx_write2buff(COMx,*puts);         //遇到停止符0結束
}
*/


/********************* UART1中斷函數************************/
void UART1_int (void) interrupt UART1_VECTOR
{
        if(RI)
        {
                RI = 0;
                if(COM1.B_RX_OK == 0)
                {
                        if(COM1.RX_Cnt >= COM_RX1_Lenth)        COM1.RX_Cnt = 0;
                        RX1_Buffer[COM1.RX_Cnt++] = SBUF;
                        COM1.RX_TimeOut = TimeOutSet1;
                }
        }

        if(TI)
        {
                TI = 0;
                if(COM1.TX_read != COM1.TX_write)
                {
                         SBUF = TX1_Buffer[COM1.TX_read];
                        if(++COM1.TX_read >= COM_TX1_Lenth)                COM1.TX_read = 0;
                }
                else        COM1.B_TX_busy = 0;
        }
}

/********************* UART2中斷函數************************/
void UART2_int (void) interrupt UART2_VECTOR
{
    if(RI2)  // 接收中斷
    {
        CLR_RI2();

        // 收到數據時,強制切回接收模式(確保模式正確)
        RS485_DIR_PIN = RS485_RX_MODE;

        if(COM2.B_RX_OK == 0)
        {
            if(COM2.RX_Cnt < COM_RX2_Lenth)  // 防止緩沖區溢出
            {
                RX2_Buffer[COM2.RX_Cnt++] = S2BUF;
                COM2.RX_TimeOut = TimeOutSet2;
            }
            else
            {
                // 緩沖區滿,清空
                COM2.RX_Cnt = 0;
                RX2_Buffer[COM2.RX_Cnt++] = S2BUF;
                COM2.RX_TimeOut = TimeOutSet2;
            }
        }
    }

    if(TI2)  // 發送中斷
    {
        CLR_TI2();

        if(COM2.TX_read != COM2.TX_write)
        {
            // 還有數據要發送
            S2BUF = TX2_Buffer[COM2.TX_read];
            if(++COM2.TX_read >= COM_TX2_Lenth) COM2.TX_read = 0;
        }
        else        
        {
            // 所有數據發送完畢
            COM2.B_TX_busy = 0;

            // 關鍵修改:延時等待最后1字節發送完成
            // 波特率9600時,1字節約1.04ms,延時1.5ms確保安全
            delay_ms(2);  // 2ms延時,確保最后1字節完全發出

            // 切換回接收模式
            RS485_DIR_PIN = RS485_RX_MODE;
        }
    }
}

char putchar(char c)
{

    if(c == '\n')
    {
        TX1_write2buff('\r');
    }
    TX1_write2buff((u8)c); // 對接硬件串口的發送緩沖,觸發中斷發送
    return c; // 按C51標準要求返回,無實際意義
}












#ifndef __USART_H
#define __USART_H         

#include        "config.h"


// ********* 485方向控制定義 *********
#define RS485_DIR_PIN   P12        // 485 DE/RE控制引腳(根據你的硬件修改)
#define RS485_TX_MODE   1          // 發送模式:DE=1, RE=1
#define RS485_RX_MODE   0          // 接收模式:DE=0, RE=0



#define        COM_TX1_Lenth        128
#define        COM_RX1_Lenth        128
#define        COM_TX2_Lenth        128
#define        COM_RX2_Lenth        128

#define        USART1        1
#define        USART2        2

#define        UART_ShiftRight        0                //同步移位輸出
#define        UART_8bit_BRTx        (1<<6)        //8位數據,可變波特率
#define        UART_9bit                (2<<6)        //9位數據,固定波特率
#define        UART_9bit_BRTx        (3<<6)        //9位數據,可變波特率

#define        UART1_SW_P30_P31        0
#define        UART1_SW_P36_P37        (1<<6)
#define        UART1_SW_P16_P17        (2<<6)        //必須使用內部時鐘
#define        UART2_SW_P10_P11        0
#define        UART2_SW_P46_P47        1


#define        TimeOutSet1                5
#define        TimeOutSet2                5

#define        BRT_Timer1        1
#define        BRT_Timer2        2

typedef struct
{
        u8        id;                                //串口號

        u8        TX_read;                //發送讀指針
        u8        TX_write;                //發送寫指針
        u8        B_TX_busy;                //忙標志

        u8         RX_Cnt;                        //接收字節計數
        u8        RX_TimeOut;                //接收超時
        u8        B_RX_OK;                //接收塊完成
} COMx_Define;

typedef struct
{
        u8        UART_Mode;                        //模式,         UART_ShiftRight,UART_8bit_BRTx,UART_9bit,UART_9bit_BRTx
        u8        UART_BRT_Use;                //使用波特率,   BRT_Timer1,BRT_Timer2
        u32        UART_BaudRate;                //波特率,       ENABLE,DISABLE
        u8        Morecommunicate;        //多機通訊允許, ENABLE,DISABLE
        u8        UART_RxEnable;                //允許接收,   ENABLE,DISABLE
        u8        BaudRateDouble;                //波特率加倍, ENABLE,DISABLE
        u8        UART_Interrupt;                //中斷控制,   ENABLE,DISABLE
        u8        UART_Polity;                //優先級,     PolityLow,PolityHigh
        u8        UART_P_SW;                        //切換端口,   UART1_SW_P30_P31,UART1_SW_P36_P37,UART1_SW_P16_P17(必須使用內部時鐘)
        u8        UART_RXD_TXD_Short;        //內部短路RXD與TXD, 做中繼, ENABLE,DISABLE

} COMx_InitDefine;

extern        COMx_Define        COM1,COM2;
extern        u8        xdata TX1_Buffer[COM_TX1_Lenth];        //發送緩沖
extern        u8         xdata RX1_Buffer[COM_RX1_Lenth];        //接收緩沖
extern        u8        xdata TX2_Buffer[COM_TX2_Lenth];        //發送緩沖
extern        u8         xdata RX2_Buffer[COM_RX2_Lenth];        //接收緩沖

u8        USART_Configuration(u8 UARTx, COMx_InitDefine *COMx);
void TX1_write2buff(u8 dat);        //寫入發送緩沖,指針+1
void TX2_write2buff(u8 dat);        //寫入發送緩沖,指針+1
void PrintString1(u8 *puts);
void PrintString2(u8 *puts);

//void COMx_write2buff(COMx_Define *COMx, u8 dat);        //寫入發送緩沖,指針+1
//void PrintString(COMx_Define *COMx, u8 *puts);
char putchar(char c);


#endif









#include "lcd12864.h"
#include        "delay.h"




sbit CS   = P3^2;     // 串行片選端:1=有效,0=無效        (對應并行輸入的RS)
sbit SID  = P3^3;     // 串行數據端:收發數據              (對應并行輸入的RW)
sbit SCK  = P3^4;     // 串行時鐘端:上升沿鎖存數據        (對應并行輸入的E)
//sbit RST  = P3^5;     // 硬件復位端:0=復位,1=正常工作    (對應并行輸入的RST)
// sbit PSB = P1^3;  // 串口模式→硬件必須直接接GND,此引腳無效

/**
***********************************************************
* @brief     串行接收1字節數據(參考代碼適配,ST7920標準)
* @return    拼接后的8位有效數據
* @note      連續讀2字節,高4位+低4位拼接,適配ST7920串口讀數據時序
***********************************************************/
static unsigned char ReceiveByte(void)
{
    unsigned char i, temp1, temp2;
    temp1 = temp2 = 0;
    // 讀高4位相關數據
    for(i=0; i<8; i++)
    {
        temp1 = temp1 << 1;
        SCK = 0;
        SCK = 1;               
        SCK = 0;
        if(SID) temp1++;
    }
    // 讀低4位相關數據
    for(i=0; i<8; i++)
    {
        temp2 = temp2 << 1;
        SCK = 0;
        SCK = 1;
        SCK = 0;
        if(SID) temp2++;
    }
    return ((0xF0 & temp1) + (0x0F & temp2)); // 拼接為8位有效數據
}

/**
***********************************************************
* @brief     串行發送1字節數據(參考代碼核心,ST7920標準時序)
* @param     dat:要發送的8位字節
* @note      
***********************************************************/
static void Lcd_SendByte(unsigned char dat)
{
    unsigned char i;
    for(i=0; i<8; i++)
    {
        SCK = 0;            // 下降沿準備數據

        SID = (dat & 0x80) != 0;  // 直接取最高位
        dat = dat << 1;

        SCK = 1;            // 上升沿鎖存數據
        SCK = 0;            // 時鐘歸0,參考代碼標準操作
    }
}

/**
***********************************************************
* @brief     檢測LCD12864忙信號(參考代碼適配,無卡死)
* @note      發0xFC讀忙前綴,循環判斷bit7,直到LCD空閑
***********************************************************/
void Lcd_12864_BusyCheck()
{
    do
    {
        Lcd_SendByte(0xFC); // 串行讀忙前綴:11111 RW(1) RS(0) 0
    }while(0x80 & ReceiveByte()); // bit7=1則忙,循環等待
}

/**
***********************************************************
* @brief     向LCD12864寫入命令(參考代碼核心,ST7920標準)
* @param     cmd:要寫入的命令字(ST7920指令集)
* @note      CS片選→忙檢測→發前綴→高4位→低4位→CS失選,嚴格按手冊
***********************************************************/
void Lcd12864_WriteCmd(unsigned char cmd)
{
    CS = 1;                // 片選有效
    Lcd_12864_BusyCheck(); // 忙檢測,參考代碼邏輯無卡死
    Lcd_SendByte(0xF8);    // 串行寫命令固定前綴:11111 RW(0) RS(0) 0
    Lcd_SendByte(0xF0 & cmd); // 發送命令高4位(屏蔽低4位)
    Lcd_SendByte(0xF0 & (cmd << 4)); // 發送命令低4位(左移后屏蔽)
    CS = 0;                // 片選無效,完成命令寫入
    delay_ms(1);           // 短延時,保證指令執行
}

/**
***********************************************************
* @brief     向LCD12864寫入數據(參考代碼核心,ST7920標準)
* @param     dat:要寫入的8位數據(漢字雙字節/ASCII字符)
* @note      寫數據前綴0xFA,其余邏輯與寫命令一致
***********************************************************/
void Lcd12864_WriteDat(unsigned char dat)
{
    CS = 1;                // 片選有效
    Lcd_12864_BusyCheck(); // 忙檢測
    Lcd_SendByte(0xFA);    // 串行寫數據固定前綴:11111 RW(0) RS(1) 0
    Lcd_SendByte(0xF0 & dat); // 發送數據高4位
    Lcd_SendByte(0xF0 & (dat << 4)); // 發送數據低4位
    CS = 0;                // 片選無效
    delay_ms(1);           // 短延時,保證數據鎖存
}

/**
***********************************************************
* @brief     LCD12864初始化函數(參考代碼標準串口流程,必顯!)
* @note      完全對齊參考代碼的初始化指令,復位+3次0x30+標準配置
***********************************************************/
void Lcd12864_Init(void)
{

//    RST = 0;
//    delay_ms(100);  // 參考代碼用100ms延時,保證硬件復位徹底
//    RST = 1;
//    delay_ms(100);  // 復位后穩定時間

    // 參考代碼核心:連續3次發0x30,確保ST7920識別并進入基礎指令集
    Lcd12864_WriteCmd(0x30);
    delay_ms(100);
    Lcd12864_WriteCmd(0x30);
    delay_ms(100);
    Lcd12864_WriteCmd(0x30);
    delay_ms(100);

    // 參考代碼標準后續配置,按順序執行
    Lcd12864_WriteCmd(0x03);  // 入口模式設置
    delay_ms(50);
    Lcd12864_WriteCmd(0x01);  // 清屏
    delay_ms(100);
    Lcd12864_WriteCmd(0x06);  // 光標移動方向配置
    delay_ms(100);
    Lcd12864_WriteCmd(0x0C);  // 開顯示、關光標、關閃爍
    delay_ms(100);
}

// 以下2個函數:完全保留你的代碼,無任何修改!!!
/**
***********************************************************
* @brief     LCD12864顯示位置定位函數
* @param     x:目標顯示行號,有效范圍1~4(LCD共4行)
* @param     y:目標顯示列號,有效范圍1~8(中文專屬,1漢字占2列)
* @return    無
* @note      x/y越界時直接返回,不執行定位;ST7920固定行起始地址映射
***********************************************************
*/
void Lcd12864_SetPos(unsigned char x, unsigned char y)
{
    unsigned char pos = 0;
    if(x < 1 || x > 4 || y < 1 || y > 8)
    {
        return;
    }
    y = y - 1;
    switch(x)
    {
        case 1 : pos = 0x80 + y; break;
        case 2 : pos = 0x90 + y; break;
        case 3 : pos = 0x88 + y; break;
        case 4 : pos = 0x98 + y; break;
        default : break;
    }
    Lcd12864_WriteCmd(pos);
}

/******************************************************************
* @brief     LCD12864寫入GB2312漢字字符串(數組傳參版)
* @param     cn:GB2312漢字字符串數組(雙字節/漢字)
* @return    無
* @note      1. 調用前必須先調用Lcd12864_SetPos定位顯示起始位置
*            2. 自動循環寫入,直到檢測到字符串結束符'\0'
*            3. 數組傳參本質等價于指針
***********************************************************/
void Lcd12864_WriteCN( unsigned char cn[])  
{
        while(*cn)  
        {
                Lcd12864_WriteDat(*cn ++);  // 逐個寫入數組元素,指針后移
        }
}




#ifndef __LCD12864_H__
#define __LCD12864_H__


#include        "config.h"

/**
***********************************************************
* @brief     LCD12864初始化函數(串口版)
* @param     無
* @return    無
* @note      純中文顯示適配,僅開啟基礎指令集,**PSB硬件接GND**
***********************************************************
*/
void Lcd12864_Init(void);   

/**
***********************************************************
* @brief     向LCD12864寫入命令(串口版)
* @param     cmd:要寫入的命令字(ST7920指令集,與并口一致)
* @return    無
* @note      寫入前自動檢測忙信號,確保LCD空閑后再操作
***********************************************************
*/
void Lcd12864_WriteCmd(unsigned char cmd);

/**
***********************************************************
* @brief     向LCD12864寫入數據(串口版)
* @param     dat:要寫入的8位數據(漢字雙字節/ASCII字符)
* @return    無
* @note      寫入前自動檢測忙信號,適配GB2312和ASCII編碼
***********************************************************
*/
void Lcd12864_WriteDat(unsigned char dat);

/**
***********************************************************
* @brief     LCD12864顯示位置定位函數(無修改)
* @param     x:目標顯示行號,有效范圍1~4(LCD共4行)
* @param     y:目標顯示列號,有效范圍1~8(中文專屬,1漢字占2列)
* @return    無
* @note      x/y越界時直接返回,不執行定位;ST7920固定行起始地址映射
***********************************************************
*/
void Lcd12864_SetPos(unsigned char x, unsigned char y);

/******************************************************************
* @brief     LCD12864寫入GB2312漢字字符串(數組傳參版)
* @param     cn:GB2312漢字字符串數組(雙字節/漢字)
* @return    無
* @note      1. 調用前必須先調用Lcd12864_SetPos定位顯示起始位置
*            2. 自動循環寫入,直到檢測到字符串結束符'\0'
*            3. 數組傳參本質等價于指針
***********************************************************/
void Lcd12864_WriteCN( unsigned char cn[]) ;







#endif





#include "config.h"
#include        "USART.h"
#include        "GPIO.h"
#include        "timer.h"


/******************** IO配置函數 **************************/
void        GPIO_config(void)
{
        GPIO_InitTypeDef        GPIO_InitStructure;                //結構定義
//  P1口定義  485使能引腳
        GPIO_InitStructure.Pin  = GPIO_Pin_2;                //指定要初始化的IO, GPIO_Pin_0 ~ GPIO_Pin_7, 或操作GPIO_Pin_All
        GPIO_InitStructure.Mode = GPIO_PullUp;                //指定IO的輸入或輸出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
        GPIO_Inilize(GPIO_P1,&GPIO_InitStructure);        //初始化
        

        GPIO_InitStructure.Pin  = GPIO_Pin_All;                //指定要初始化的IO, GPIO_Pin_0 ~ GPIO_Pin_7, 或操作GPIO_Pin_All
        GPIO_InitStructure.Mode = GPIO_PullUp;                //指定IO的輸入或輸出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
        GPIO_Inilize(GPIO_P0,&GPIO_InitStructure);        //初始化
        
        //P3口定義  LCD12864        
        GPIO_InitStructure.Pin  = GPIO_Pin_2;                //指定要初始化的IO, GPIO_Pin_0 ~ GPIO_Pin_7, 或操作
        GPIO_InitStructure.Mode = GPIO_PullUp;                //指定IO的輸入或輸出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
        GPIO_Inilize(GPIO_P3,&GPIO_InitStructure);        //初始化
        
        GPIO_InitStructure.Pin  = GPIO_Pin_3;                //指定要初始化的IO, GPIO_Pin_0 ~ GPIO_Pin_7, 或操作
        GPIO_InitStructure.Mode = GPIO_PullUp;                //指定IO的輸入或輸出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
        GPIO_Inilize(GPIO_P3,&GPIO_InitStructure);        //初始化
        
        GPIO_InitStructure.Pin  = GPIO_Pin_4;                //指定要初始化的IO, GPIO_Pin_0 ~ GPIO_Pin_7, 或操作
        GPIO_InitStructure.Mode = GPIO_PullUp;                //指定IO的輸入或輸出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
        GPIO_Inilize(GPIO_P3,&GPIO_InitStructure);        //初始化
        
        GPIO_InitStructure.Pin  = GPIO_Pin_5;                //指定要初始化的IO, GPIO_Pin_0 ~ GPIO_Pin_7, 或操作
        GPIO_InitStructure.Mode = GPIO_PullUp;                //指定IO的輸入或輸出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
        GPIO_Inilize(GPIO_P3,&GPIO_InitStructure);        //初始化
        
        
}


/************************ 定時器配置 ****************************/
void        Timer_config(void)
{
        
//初值為1000時,為1ms定時器        
        TIM_InitTypeDef                TIM_InitStructure;                                        //結構定義
        TIM_InitStructure.TIM_Mode      = TIM_16BitAutoReload;        //指定工作模式,   TIM_16BitAutoReload,TIM_16Bit,TIM_8BitAutoReload,TIM_16BitAutoReloadNoMask
        TIM_InitStructure.TIM_Polity    = PolityLow;                        //指定中斷優先級, PolityHigh,PolityLow
        TIM_InitStructure.TIM_Interrupt = ENABLE;                                //中斷是否允許,   ENABLE或DISABLE
        TIM_InitStructure.TIM_ClkSource = TIM_CLOCK_1T;                        //指定時鐘源,     TIM_CLOCK_1T,TIM_CLOCK_12T,TIM_CLOCK_Ext
        TIM_InitStructure.TIM_ClkOut    = ENABLE;                                //是否輸出高速脈沖, ENABLE或DISABLE
        TIM_InitStructure.TIM_Value     = 65536UL - (MAIN_Fosc / 1000);                //初值, 1/2 = 0.5KHZ = 500HZ
        TIM_InitStructure.TIM_Run       = ENABLE;                                //是否初始化后啟動定時器, ENABLE或DISABLE
        Timer_Inilize(Timer0,&TIM_InitStructure);                                //初始化Timer0          Timer0,Timer1,Timer2

////初值為1000時,為1ms定時器
//        TIM_InitStructure.TIM_Mode      = TIM_16BitAutoReload;        //指定工作模式,   TIM_16BitAutoReload,TIM_16Bit,TIM_8BitAutoReload,TIM_16BitAutoReloadNoMask
//        TIM_InitStructure.TIM_Polity    = PolityLow;                        //指定中斷優先級, PolityHigh,PolityLow
//        TIM_InitStructure.TIM_Interrupt = ENABLE;                                //中斷是否允許,   ENABLE或DISABLE
//        TIM_InitStructure.TIM_ClkSource = TIM_CLOCK_1T;                        //指定時鐘源, TIM_CLOCK_1T,TIM_CLOCK_12T,TIM_CLOCK_Ext
//        TIM_InitStructure.TIM_ClkOut    = ENABLE;                                //是否輸出高速脈沖, ENABLE或DISABLE
//        TIM_InitStructure.TIM_Value     = 65536UL - (MAIN_Fosc / 1000);                //初值, 1/2 = 0.5KHZ = 500HZ
//        TIM_InitStructure.TIM_Run       = ENABLE;                                //是否初始化后啟動定時器, ENABLE或DISABLE
//        Timer_Inilize(Timer1,&TIM_InitStructure);                                //初始化Timer1          Timer0,Timer1,Timer2

////初值為50時,為20ms定時器
//        TIM_InitStructure.TIM_Interrupt = ENABLE;                                //中斷是否允許,   ENABLE或DISABLE. (注意: Timer2固定為16位自動重裝, 中斷固定為低優先級)
//        TIM_InitStructure.TIM_ClkSource = TIM_CLOCK_12T;                //指定時鐘源,     TIM_CLOCK_1T,TIM_CLOCK_12T,TIM_CLOCK_Ext
//        TIM_InitStructure.TIM_ClkOut    = ENABLE;                                //是否輸出高速脈沖, ENABLE或DISABLE
//        TIM_InitStructure.TIM_Value     = 65536UL - (MAIN_Fosc / (50*12));                //初值 0.5/2=0.025KHZ = 25HZ
//        TIM_InitStructure.TIM_Run       = ENABLE;                                //是否初始化后啟動定時器, ENABLE或DISABLE
//        Timer_Inilize(Timer2,&TIM_InitStructure);                                //初始化Timer2          Timer0,Timer1,Timer2
}














/*************  外部函數和變量聲明 *****************/

void        UART_config(void)
{
        COMx_InitDefine                COMx_InitStructure;                                        //結構定義
        COMx_InitStructure.UART_Mode      = UART_8bit_BRTx;                //模式,       UART_ShiftRight,UART_8bit_BRTx,UART_9bit,UART_9bit_BRTx
        COMx_InitStructure.UART_BRT_Use   = BRT_Timer2;                        //使用波特率,   BRT_Timer1, BRT_Timer2 (注意: 串口2固定使用BRT_Timer2)
        COMx_InitStructure.UART_BaudRate  = 9600ul;                        //波特率, 一般 110 ~ 115200
        COMx_InitStructure.UART_RxEnable  = ENABLE;                                //接收允許,   ENABLE或DISABLE
        COMx_InitStructure.BaudRateDouble = DISABLE;                        //波特率加倍, ENABLE或DISABLE
        COMx_InitStructure.UART_Interrupt = ENABLE;                                //中斷允許,   ENABLE或DISABLE
        COMx_InitStructure.UART_Polity    = PolityLow;                        //中斷優先級, PolityLow,PolityHigh
        COMx_InitStructure.UART_P_SW      = UART1_SW_P30_P31;        //切換端口,   UART1_SW_P30_P31,UART1_SW_P36_P37,UART1_SW_P16_P17(必須使用內部時鐘)
        COMx_InitStructure.UART_RXD_TXD_Short = DISABLE;                //內部短路RXD與TXD, 做中繼, ENABLE,DISABLE
        USART_Configuration(USART1, &COMx_InitStructure);                //初始化串口1 USART1,USART2

        COMx_InitStructure.UART_Mode      = UART_8bit_BRTx;                //模式,       UART_ShiftRight,UART_8bit_BRTx,UART_9bit,UART_9bit_BRTx
        COMx_InitStructure.UART_BaudRate  = 9600ul;                        //波特率,     110 ~ 115200
        COMx_InitStructure.UART_RxEnable  = ENABLE;                                //接收允許,   ENABLE或DISABLE
        COMx_InitStructure.UART_Interrupt = ENABLE;                                //中斷允許,   ENABLE或DISABLE
        COMx_InitStructure.UART_Polity    = PolityLow;                        //中斷優先級, PolityLow,PolityHigh
        COMx_InitStructure.UART_P_SW      = UART2_SW_P10_P11;        //切換端口,   UART2_SW_P10_P11,UART2_SW_P46_P47
        USART_Configuration(USART2, &COMx_InitStructure);                //初始化串口2 USART1,USART2

//        PrintString1("STC15F2K60S2 UART1 Test Prgramme!\r\n");        //SUART1發送一個字符串
        PrintString2("STC15F2K60S2 UART2 Test Prgramme!\r\n");        //SUART2發送一個字符串
}








#ifndef                __CONFIG_H
#define                __CONFIG_H


/*********************************************************/

#define MAIN_Fosc                22118400L        //定義主時鐘
//#define MAIN_Fosc                12000000L        //定義主時鐘
//#define MAIN_Fosc                11059200L        //定義主時鐘
//#define MAIN_Fosc                 5529600L        //定義主時鐘
//#define MAIN_Fosc                24000000L        //定義主時鐘


/*********************************************************/

#include        "STC15Fxxxx.H"

void        UART_config(void);
void        GPIO_config(void);
void        Timer_config(void);

#endif















分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享淘帖 頂 踩
回復

使用道具 舉報

沙發
ID:844772 發表于 2026-3-19 08:52 | 只看該作者
就應該刪掉,因為就一個總線,它可能導致總線沖突
回復

使用道具 舉報

板凳
ID:384109 發表于 2026-3-19 09:15 | 只看該作者
485總線沖突了,同一個總線上的數據不可能相互獨立的
回復

使用道具 舉報

地板
ID:1151496 發表于 2026-3-19 12:16 | 只看該作者
glinfei 發表于 2026-3-19 08:52
就應該刪掉,因為就一個總線,它可能導致總線沖突

485總線本身就可以掛載多個設備,我還想再添加幾個
回復

使用道具 舉報

5#
ID:1151496 發表于 2026-3-19 12:20 | 只看該作者
現在我把風速和溫濕度的函數拆分開來,在主函數里定時調用,可以顯示風速和溫濕度了。不知道還有沒有更好的方法?

/**
* @brief 任務1運行 讀取溫濕度
*/
void Task1_TempHumi_Run(void)
{
    // ========== 所有變量在函數開頭定義 ==========
    // 時間相關變量
    static u32 xdata lastWindQueryTime = 0;    // 上次風速查詢時間
    static u32 xdata lastTempQueryTime = 0;    // 上次溫濕度查詢時間
    static u32 xdata lastDisplayTime = 0;      // 上次顯示更新時間
   
    // 上次顯示值(用于比較是否變化)
    static u16 xdata lastWindSpeed = 0;
    static u16 xdata lastWindLevel = 0;
    static int xdata lastTemp = 0;
    static u16 xdata lastHumi = 0;
   
    // 風速狀態機變量
    static u8 xdata windStep = 0;        // 0:空閑, 1:等待響應
    static u32 xdata windStartTime = 0;   // 風速請求發送時間
   
    // 溫濕度狀態機變量
    static u8 xdata tempStep = 0;         // 0:空閑, 1:等待響應
    static u32 xdata tempStartTime = 0;    // 溫濕度請求發送時間
   
    // 當前時間(非靜態,每次調用重新獲取)
    u32 currentTime;
   
    // ========== 函數體開始 ==========
    currentTime = GetSysTimeMs();
   
   
       
            // ========== 溫濕度查詢(每2000ms一次)==========
    if (tempStep == 0)  // 只在空閑狀態才能發送新請求
    {
        if (currentTime - lastTempQueryTime >= 1000)
        {
            ModbusMasterSendTempHumiData();  // 發送溫濕度查詢碼
            tempStep = 1;
            tempStartTime = currentTime;
            lastTempQueryTime = currentTime;  // 更新查詢時間
            printf("發送溫濕度請求...\n");
        }
    }
       
    // ========== 處理溫濕度響應 ==========
    if (tempStep == 1)
    {
        ModbusMasterReceiveTempHumi();
        
        // 接收完成
        if (COM2.RX_TimeOut == 0 && COM2.RX_Cnt == 0)
        {
            tempStep = 0;  // 回到空閑狀態
            printf("溫濕度接收完成\n");
        }
        // 超時處理(500ms無響應)
        else if (currentTime - tempStartTime > 500)
        {
            printf("溫濕度響應超時\n");
            tempStep = 0;
            COM2.RX_Cnt = 0;  // 清空接收計數器
        }
    }
   
    // ========== 更新LCD顯示==========


        
        if (temp != lastTemp || humi != lastHumi)
        {
            Temperature_Display(temp, 3, 4);
            Humidity_Display(humi, 4, 4);
            printf("LCD更新 - 溫度:%d.%d℃ 濕度:%u.%u%%\n",
                   temp/10, (temp<0 ? -(temp%10) : temp%10),
                   humi/10, humi%10);
            lastTemp = temp;
            lastHumi = humi;
        }

   

}




/**
* @brief 任務1運行  讀取風速風力
*/
void Task1_Wind_Run(void)
{
    // ========== 所有變量在函數開頭定義 ==========
    // 時間相關變量
    static u32 xdata lastWindQueryTime = 0;    // 上次風速查詢時間

    static u32 xdata lastDisplayTime = 0;      // 上次顯示更新時間
   
    // 上次顯示值(用于比較是否變化)
    static u16 xdata lastWindSpeed = 0;
    static u16 xdata lastWindLevel = 0;

   
    // 風速狀態機變量
    static u8 xdata windStep = 0;        // 0:空閑, 1:等待響應
    static u32 xdata windStartTime = 0;   // 風速請求發送時間
   
    // 溫濕度狀態機變量

   
    // 當前時間(非靜態,每次調用重新獲取)
    u32 xdata currentTime;
   
    // ========== 函數體開始 ==========
    currentTime = GetSysTimeMs();
   
    // ========== 風速查詢(每1000ms一次)==========
    if (windStep == 0)  // 只在空閑狀態才能發送新請求
    {
        if (currentTime - lastWindQueryTime >= 1000)
        {
            ModbusMasterSendWindData();  // 發送風速查詢碼
            windStep = 1;
            windStartTime = currentTime;
            lastWindQueryTime = currentTime;  // 更新查詢時間
            printf("發送風速請求...\n");
        }
    }
   

   
    // ========== 處理風速響應 ==========
    if (windStep == 1)
    {
        ModbusMasterReceiveWind();
        
        // 接收完成(COM2接收超時且計數為0)
        if (COM2.RX_TimeOut == 0 && COM2.RX_Cnt == 0)
        {
            windStep = 0;  // 回到空閑狀態
            printf("風速接收完成\n");
        }
        // 超時處理(500ms無響應)
        else if (currentTime - windStartTime > 500)
        {
            printf("風速響應超時\n");
            windStep = 0;
            COM2.RX_Cnt = 0;  // 清空接收計數器
        }
    }
   
       

   
    // ========== 更新LCD顯示==========

        
        if (windSpeed != lastWindSpeed || windLevel != lastWindLevel)
        {
            WindSpeed_Display(windSpeed, 1, 4);
            WindLevel_Display(windLevel, 2, 4);
            printf("LCD更新 - 風速:%u(%.2f) 風級:%u\n",
                   windSpeed, windSpeed * 0.01f, windLevel);
            lastWindSpeed = windSpeed;
            lastWindLevel = windLevel;
        }
        
   

   
   
}


void main(void)
{
        u8        i;
    u8 key_val;
        u32 xdata  run_time;
        u32 xdata  run_time2;

       
       
        Timer_config();
        UART_config();
        GPIO_config();
        Lcd12864_Init();
        EA = 1;

        Task1_Init();
        printf("Init is finish\n");
        while (1)
        {
                run_time = GetSysTimeMs();
                if(run_time - run_time2 >= 1100)
                {
                        run_time2 = run_time;
                        P00 = ~P00;
                }
  
               
       if(P00 == 0)
           {
                        Task1_TempHumi_Run();
           }
        
           else
           Task1_Wind_Run();


        }
}

回復

使用道具 舉報

6#
ID:384109 發表于 2026-3-20 09:23 | 只看該作者
這本身就是你自己在通訊過程中造成的設備間的沖突,找錯問題方向了
回復

使用道具 舉報

7#
ID:844772 發表于 2026-3-24 10:00 | 只看該作者
能用就行啦,優化要理解,為啥你共用COM2作緩存會沖突。
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表