恍如隔世 发表于 2025-7-29 10:36:12

8G1K08A串口问题求助

#include "STC8G.h"
#include "intrins.h"

// 宏定义
#define FOSC      11059200UL// 晶振频率(11.0592MHz)
#define BAUD      9600      // 波特率
#define WDT_TIMEOUT 0x07      // 看门狗超时时间(0x07对应最长超时,约18ms@11.0592MHz)

// 全局变量:5秒计时计数器(定时器0每10ms中断一次,累计500次为5秒)
unsigned int count_5s = 0;
// 待发送的数据
unsigned char sendData[] = {0x3A, 0x16, 0xA0, 0x01, 0x01, 0xB8, 0x00, 0x0D, 0x0A};
#define DATA_LEN    sizeof(sendData)/sizeof(sendData)

// 初始化看门狗
void WDT_Init(void) {
    WDT_CONTR = WDT_TIMEOUT;// 设置超时时间
    WDT_CONTR |= 0x10;      // 启动看门狗
    EA = 1;                   // 允许总中断(看门狗溢出会复位,无需中断使能)
}

// 喂狗函数(定时调用,防止看门狗复位)
void WDT_Feed(void) {
    WDT_CONTR |= 0x08;// 重新装载看门狗计数器
}

// 初始化定时器0(用于10ms定时中断)
void Timer0_Init(void) {
    TMOD &= 0xF0;// 清除定时器0配置
    TMOD |= 0x01;// 定时器0工作在方式1(16位定时)
    // 计算初值(10ms@11.0592MHz,12T模式)
    TH0 = (65536 - (FOSC / 12 / 100)) / 256;// 100Hz = 10ms
    TL0 = (65536 - (FOSC / 12 / 100)) % 256;
    ET0 = 1;       // 允许定时器0中断
    TR0 = 1;       // 启动定时器0
    EA = 1;      // 允许总中断
}

// 定时器0中断服务函数(每10ms触发一次)
void Timer0_ISR(void) interrupt 1 {
    // 重新装载初值
    TH0 = (65536 - (FOSC / 12 / 100)) / 256;
    TL0 = (65536 - (FOSC / 12 / 100)) % 256;

    count_5s++;      // 每10ms计数+1
    if (count_5s >= 500) {// 500*10ms = 5000ms = 5秒
      count_5s = 0;       // 重置计数器
    }

    WDT_Feed();// 每10ms喂一次狗(远小于看门狗超时时间)
}

// 初始化串口
void UART_Init(void) {
    // 配置TXD引脚(P3.1)为推挽输出
    P3M0 = 0x02;// P3.1推挽输出
    P3M1 = 0x00;

    // 配置波特率(定时器1方式2)
    TMOD &= 0x0F;
    TMOD |= 0x20;// 定时器1方式2(8位自动重装载)
    TH1 = (unsigned char)(256 - (FOSC / (BAUD * 12 * 16)));
    TL1 = TH1;
    TR1 = 1;       // 启动定时器1

    SCON = 0x50;   // 串口方式1(8位数据)
    ES = 0;      // 关闭串口中断(仅发送)
}

// 串口发送单个字节
void UART_SendByte(unsigned char dat) {
    SBUF = dat;
    while (!TI);// 等待发送完成
    TI = 0;       // 清除标志位
}

// 发送数据数组
void UART_SendArray(unsigned char *arr, unsigned char len) {
    unsigned char i;
    for (i = 0; i < len; i++) {
      UART_SendByte(arr);
    }
}

void main(void) {
    UART_Init();    // 初始化串口
    Timer0_Init();// 初始化定时器0(10ms中断)
    WDT_Init();   // 初始化并启动看门狗

    while (1) {
      if (count_5s == 0) {// 每5秒触发一次发送
            UART_SendArray(sendData, DATA_LEN);
            // 发送完成后等待计数器重新计数,避免重复发送
            while (count_5s == 0);
      }
    }
}
我让串口发送0x3A, 0x16, 0xA0, 0x01, 0x01, 0xB8, 0x00, 0x0D, 0x0A,使用11059200频率下载,接收的字符串不对,当我把下载频率调331776就真确了,请问下是那里出错了

国芯人工智能 发表于 2025-7-29 10:38:00

STC8G1K08A串口问题求助回复如下:

尊敬的用户,您好!

感谢您提交关于STC8G1K08A串口通信的问题。根据您提供的代码片段,我们对代码逻辑、配置以及潜在问题进行了分析,并针对可能存在的问题给出以下专业建议。

一、代码结构与配置分析

您在代码中使用了#include "STC8Gh"和#include "intrinsh"头文件,这是STC8系列单片机的标准头文件,用于访问寄存器和内置函数。但需要注意的是,intrinsh.h并非标准头文件,可能是误写或非官方库文件。建议确认是否为intrins.h(用于内联汇编函数),并确保开发环境正确配置。

二、串口初始化问题

您的代码片段中并未完整展示串口初始化部分,仅展示了定时器0和看门狗的配置。因此无法判断串口是否正确配置。以下为标准的STC8G1K08A串口初始化步骤:

1. 设置波特率:通过定时器1或模式2进行串口波特率设置。
2. 配置串口工作方式:选择方式0、方式1、方式2或方式3。
3. 使能串口中断(如需)。
4. 开启串口接收/发送功能。

三、常见串口问题排查建议

1. 波特率不匹配:请检查实际使用的晶振频率是否与代码中定义的FOSC一致。若使用外部晶振,请确保其稳定性和准确度。

2. 串口未正确初始化:请补充完整的串口初始化代码,例如:

c
void UARTInit(void) {
    SCON = 0x50;      // 设置为方式1(8位异步串行通信)
    TMOD |= 0x20;       // 定时器1工作方式2
    TH1 = 0xFD;         // 波特率9600(基于11.0592MHz)
    TL1 = 0xFD;
    TR1 = 1;            // 启动定时器1
    ES = 1;             // 使能串口中断
    EA = 1;             // 允许全局中断
}

3. 串口发送逻辑缺失:当前代码中仅有数据数组sendData[],但未看到发送函数实现。请补充串口发送函数,例如:

c
void UARTSendByte(unsigned char data) {
    SBUF = data;
    while (!TI);      // 等待发送完成
    TI = 0;             // 清除发送标志
}

void UARTSendString(unsigned char str, unsigned int len) {
    for (unsigned int i = 0; i < len; i++) {
      UARTSendByte(str);
    }
}

4. 看门狗配置问题:您已启用看门狗,但未提供喂狗机制的具体调用位置。建议在主循环中定期调用WDTFeed(),以避免因长时间未喂狗导致复位。

四、其他建议
调试工具:建议使用示波器或逻辑分析仪检测串口TXD引脚信号,确认是否有数据输出。
电源稳定性:确保MCU供电电压稳定,避免因电压波动导致通信异常。
引脚配置:确认串口TXD和RXD引脚是否已正确配置为输出和输入模式。

五、总结

综上所述,您的代码存在以下潜在问题:
串口初始化未完整;
缺乏串口发送函数;
看门狗喂狗机制未明确调用位置;
intrinsh.h可能为误写。

建议您完善串口初始化代码,添加发送函数,并确保看门狗定时喂狗。如仍存在问题,可进一步提供完整代码或硬件连接图以便深入分析。

如需进一步技术支持,欢迎随时联系国芯人工智能团队。

祝您开发顺利!

[本文内容由国芯人工智能辅助生成,仅供参考]

ercircle 发表于 2025-7-29 11:02:02


开EAXFR:

小工具计算波特率:




不建议在声明时赋初值,最好改在函数内赋值,data的直接被清零了:

#include "STC8G.h"
#include "intrins.h"

// 宏定义
#define FOSC      11059200UL// 晶振频率(11.0592MHz)
#define BAUD      9600      // 波特率
#define WDT_TIMEOUT 0x07      // 看门狗超时时间(0x07对应最长超时,约18ms@11.0592MHz)

// 全局变量:5秒计时计数器(定时器0每10ms中断一次,累计500次为5秒)
unsigned int count_5s = 0;
// 待发送的数据
unsigned char xdata sendData[] = {0x3A, 0x16, 0xA0, 0x01, 0x01, 0xB8, 0x00, 0x0D, 0x0A};
#define DATA_LEN    sizeof(sendData)/sizeof(sendData)

// 初始化看门狗
void WDT_Init(void) {
    WDT_CONTR = WDT_TIMEOUT;// 设置超时时间
    WDT_CONTR |= 0x10;      // 启动看门狗
    EA = 1;                   // 允许总中断(看门狗溢出会复位,无需中断使能)
}

// 喂狗函数(定时调用,防止看门狗复位)
void WDT_Feed(void) {
    WDT_CONTR |= 0x08;// 重新装载看门狗计数器
}

// 初始化定时器0(用于10ms定时中断)
void Timer0_Init(void) {
    TMOD &= 0xF0;// 清除定时器0配置
    TMOD |= 0x01;// 定时器0工作在方式1(16位定时)
    // 计算初值(10ms@11.0592MHz,12T模式)
    TH0 = (65536 - (FOSC / 12 / 100)) / 256;// 100Hz = 10ms
    TL0 = (65536 - (FOSC / 12 / 100)) % 256;
    ET0 = 1;       // 允许定时器0中断
    TR0 = 1;       // 启动定时器0
    EA = 1;      // 允许总中断
}

// 定时器0中断服务函数(每10ms触发一次)
void Timer0_ISR(void) interrupt 1 {
    // 重新装载初值
    TH0 = (65536 - (FOSC / 12 / 100)) / 256;
    TL0 = (65536 - (FOSC / 12 / 100)) % 256;

    count_5s++;      // 每10ms计数+1
    if (count_5s >= 500) {// 500*10ms = 5000ms = 5秒
      count_5s = 0;       // 重置计数器
    }

    WDT_Feed();// 每10ms喂一次狗(远小于看门狗超时时间)
}

// 初始化串口
void UART_Init(void) {
    // 配置TXD引脚(P3.1)为推挽输出
    P3M0 = 0x02;// P3.1推挽输出
    P3M1 = 0x00;

    // 配置波特率(定时器1方式2)
//    TMOD &= 0x0F;
//    TMOD |= 0x20;// 定时器1方式2(8位自动重装载)
//    TH1 = (unsigned char)(256 - (FOSC / (BAUD * 12 * 16)));
//    TL1 = TH1;
//    TR1 = 1;       // 启动定时器1

//    SCON = 0x50;   // 串口方式1(8位数据)
//    ES = 0;      // 关闭串口中断(仅发送)
      
                PCON &= 0x7F;                //波特率不倍速
      SCON = 0x50;                //8位数据,可变波特率
      AUXR |= 0x40;                //定时器时钟1T模式
      AUXR &= 0xFE;                //串口1选择定时器1为波特率发生器
      TMOD &= 0x0F;                //设置定时器模式
      TMOD |= 0x20;                //设置定时器模式
      TL1 = 0xDC;                        //设置定时初始值
      TH1 = 0xDC;                        //设置定时重载值
      ET1 = 0;                        //禁止定时器中断
      TR1 = 1;                        //定时器1开始计时
      
//      SCON = 0x50;                //8位数据,可变波特率
//      AUXR |= 0x40;                //定时器时钟1T模式
//      AUXR &= 0xFE;                //串口1选择定时器1为波特率发生器
//      TMOD &= 0x0F;                //设置定时器模式
//      TL1 = 0xE0;                        //设置定时初始值
//      TH1 = 0xFE;                        //设置定时初始值
//      ET1 = 0;                        //禁止定时器中断
//      TR1 = 1;                        //定时器1开始计时
}

// 串口发送单个字节
void UART_SendByte(unsigned char dat) {
    SBUF = dat;
    while (!TI);// 等待发送完成
    TI = 0;       // 清除标志位
}

// 发送数据数组
void UART_SendArray(unsigned char *arr, unsigned char len) {
    unsigned char i;
    for (i = 0; i < len; i++) {
      UART_SendByte(arr);
    }
}

void main(void) {
                        P_SW2=0x80;
                P0M0 = 0x00; P0M1 = 0x00;
                P1M0 = 0x00; P1M1 = 0x00;
                P2M0 = 0x00; P2M1 = 0x00;
                P3M0 = 0x00; P3M1 = 0x00;
                P4M0 = 0x00; P4M1 = 0x00;
                P5M0 = 0x00; P5M1 = 0x00;
                P6M0 = 0x00; P6M1 = 0x00;
                P7M0 = 0x00; P7M1 = 0x00;
      
    UART_Init();    // 初始化串口
    Timer0_Init();// 初始化定时器0(10ms中断)
    WDT_Init();   // 初始化并启动看门狗

    while (1) {
      if (count_5s == 0) {// 每5秒触发一次发送
            UART_SendArray(sendData, DATA_LEN);
            // 发送完成后等待计数器重新计数,避免重复发送
            while (count_5s == 0);
      }
    }
}



网老四 发表于 2025-7-29 11:07:17

TH1 = (unsigned char)(256 - (FOSC / (BAUD * 12 * 16)));

这里计算 (BAUD * 12 * 16), BAUD是int型
9600*12*16=1843200溢出了吧?

恍如隔世 发表于 2025-7-29 12:24:24

ercircle 发表于 2025-7-28 15:02
开EAXFR:

小工具计算波特率:


晚上我试试
页: [1]
查看完整版本: 8G1K08A串口问题求助