找回密码
 立即注册
查看: 219|回复: 11

STC8H1K17T,串口1定位到P36/P37失败!

[复制链接]

27

主题

153

回帖

901

积分

高级会员

积分
901
发表于 2026-10-11 08:58:32 | 显示全部楼层 |阅读模式
//一、串口收发是基于DMA传送的。故中断中没啥实质性操作:
//-----------------------------------------------------
void S1_Intr(void) interrupt 4
{        //---------------------------------------------
        if(RI)                //接收分支
        {        RI = 0;                //清除RI位
                //........................
                rOv_cn = 0;        //清超时计数
                Rxd_In = 1;        //标记正在接收
                X_Out = ~X_Out;        // LED指示灯!
        }
        //---------------------------------------------
        if(TI)                //发送分支
        {        TI = 0;                //清除TI2位
        }
}

//二、请直接看串口设置:
//=====================================================
#define MAIN_Fosc        22118400UL
//-----------------------------------------------------
//串口1初始化:
void S1_Init(u16 Baud)
{        u16 Tn_IV;
        Tn_IV = (65536UL-MAIN_Fosc/4/Baud);
        //---------- P_SW1: S1_S[1:0]=>_RxD/_TxD ------------
        P_SW1 &= 0x3F;                //b7b6=00=>P3.0/P3.1
        P_SW1 |= 0x40;                //b7b6=01=>P3.6/P3.7    // 此行注释,在P30/P31上正常!
//        P_SW1 |= 0x80;                //b7b6=10=>P1.6/P1.7
//        P_SW1 |= 0xC0;                //b7b6=11=>P4.3/P4.4
        //-----------------------------------------------------------------
        ES = 0;
        //-----------------------------------------------------------------
        PCON &= 0x7F;                //波特率不倍速
        SCON = 0x50;                //8位数据,可变波特率
        //-----------------------------------------------------------------
        AUXR |= 0x40;        //T1时钟为Fosc,即1T
        AUXR &= 0xFE;        //串口1选择T1为波特率发生器
        TMOD &= 0x0F;        //设定T1为16位自动重装方式
        TL1 = (u8)(Tn_IV & 0xFF);
        TH1 = (u8)(Tn_IV >> 8);
        ET1 = 0;                //禁止定时器1中断
        TR1 = 1;                //启动定时器1
        //------------------------------------------------------------------
        ES = 1;                        //开放S1中断
        //------------------------------------------------------------------
}

//三、因为在P30/P31上正常,故认为代码没问题,DMA配置代码就不贴了。




回复

使用道具 举报 送花

已绑定手机

872

主题

1万

回帖

2万

积分

管理员

积分
25428
发表于 2026-10-11 09:29:11 | 显示全部楼层
截图202610110929005166.jpg
回复

使用道具 举报 送花

已绑定手机

872

主题

1万

回帖

2万

积分

管理员

积分
25428
发表于 2026-10-11 09:29:31 | 显示全部楼层

现在问题非常清楚了。结合手册和论坛信息,我来给您完整解答。


问题分析:STC8H1K17T 串口1切换到 P3.6/P3.7 失败

结论:不是寄存器写错,而是封装引脚本身的问题

从您贴出的代码看,P_SW1 的设置逻辑是正确的:

P_SW1 &= 0x3F;                //先清零 b7b6,S1_S[1:0]=00
P_SW1 |= 0x40;                //b7b6=01,S1_S[1:0]=01 => P3.6/P3.7

对照《功能脚切换》章节中 P_SW1 寄存器的 S1_S[1:0] 定义:

S1_S[1:0] RxD TxD
00 P3.0 P3.1
01 P3.6 P3.7
10 P1.6 P1.7
11 P4.3 P4.4

0x40 对应 S1_S[1:0]=01,理论上就是切到 P3.6/P3.7,这一点没错。P30/P31 能正常通信,也说明波特率、T1 设置等都没问题。

真正的原因是您用的 STC8H1K17T 封装没有引出这两个引脚(或对应引脚被占用)。

关键依据

根据《STC8H系列各子系列选型简介、特性/价格/管脚图》章节:

STC8H1K17T 属于 STC8H1K08T 系列,可选封装为 TSSOP20 / QFN20 / SOP16 / SOP20。其中:

  • P3.6(RxD_2)只在 TSSOP20 的第 17 脚、QFN20 的第 14 脚上才有引出;
  • P3.7(TxD_2)只在 TSSOP20 的第 18 脚、QFN20 的第 15 脚上才有引出;
  • SOP16 封装中,第 15、16 脚分别是 P3.6、P3.7(SOP16 编号 15=P3.6,16=P3.7)——注意这里是 SOP16 编号,与 TSSOP20 的编号不同。

也就是说,关键要看您实际用的是哪种封装:

  • 如果您用的是 SOP16:P3.6/P3.7 是有引出的(SOP16 的第 15、16 脚),此时切换失败要检查该引脚是否被外部电路拉死、是否配置为输出、焊接是否正常。
  • 如果您用的是 20 脚封装(TSSOP20/QFN20) 的某些版本,或者实际芯片型号/丝印与您以为的不符,则可能根本没有这些引脚。

论坛上同类问题的印证

据论坛用户反馈,多个使用 STC8H1K17T 的用户都遇到了"在 STC8H1K08T 上正常、换到 STC8H1K17T 上就不正常"的情况(帖子 TID 11147《STC8H1K17T串口疑问》,以及 TID 22647《STC8H1K17T P1.6,P1.7 控制无反应》)。其中 TID 22647 里一位用户贴出 P1.6/P1.7 无法控制,最终原因是 STC8H1K17T 属于 STC8H1K08T 系列,16 脚封装芯片并没有 P1.6、P1.7 引脚。

建议您按以下步骤排查

  1. 先确认实物封装的引脚数:芯片丝印和封装是 SOP16 还是 TSSOP20/QFN20?P3.6/P3.7 是否在您这个封装上真正引出了。
  2. 测量引脚是否有波形:把 P_SW1 切到 01 后,直接用示波器/逻辑分析仪量 P3.6、P3.7 是否有收发波形输出(不接任何外设,先空脚测)。
  3. 检查引脚复用冲突:P3.6 还复用 INT2、CMP-、ADC14、TK14;P3.7 复用 INT3、CMP+、TK15。如果这些功能被意外使能,可能干扰串口。
  4. 确认 P3.6/P3.7 的 I/O 模式:TxD 需要配置为输出(推挽或准双向),若配成了高阻输入则发不出数据。
  5. 若确实是无引脚的封装:只能改用 P3.0/P3.1(默认脚)或 P1.6/P1.7(S1_S=10)等本封装实际存在的引脚组。

如果您能告诉我具体封装形式(SOP16 / TSSOP20 / QFN20 / SOP20),我可以帮您对照引脚表,精确确认 P3.6/P3.7 到底有没有被引出,从而给出针对性的解决方案。


🔍 搜索 "STC 单片机 论坛 帖子"

⏱️ 查找用时 14.6s | 总回答用时 20.2s

回复

使用道具 举报 送花

已绑定手机

872

主题

1万

回帖

2万

积分

管理员

积分
25428
发表于 2026-10-11 09:32:51 | 显示全部楼层

AI助手这次分析错了,
TSSOP20, SOP16, QFN20, 都有 P3.6/P3.7

截图202610110931038296.jpg


截图202610110931448340.jpg

截图202610110932204602.jpg
回复

使用道具 举报 送花

已绑定手机

872

主题

1万

回帖

2万

积分

管理员

积分
25428
发表于 2026-10-11 09:34:20 | 显示全部楼层

您说得对,我上一条回复有误,向您致歉并更正:

更正说明

根据《STC8H系列各子系列选型简介、特性/价格/管脚图》章节中 STC8H1K08T/STC8H1K17T 的"不同封装形式管脚对应功能说明"表格,P3.6 和 P3.7 在 TSSOP20、QFN20、SOP16 三种封装中均有引出:

引脚 TSSOP20 编号 QFN20 编号 SOP16 编号 复用功能
P3.6 17 14 15 INT2、RxD_2(串口1接收)、CMP-、ADC14、TK14
P3.7 18 15 16 INT3、TxD_2(串口1发送)、CMP+、TK15

我上一条回复中说的"SOP16 封装没有 P3.6/P3.7"是错误的——那是论坛帖(TID 22647)里针对 P1.6/P1.7 的结论,我错误地张冠李戴到 P3.6/P3.7 上了。P3.6/P3.7 在您的 TSSOP20/SOP16/QFN20 封装上都是实实在在引出来的。

那么关于 TID 22647 里"16脚封装没有 P1.6/P1.7"这个说法的准确性问题,我上一轮检索的引脚表里,P1.6/P1.7 的 SOP16 编号栏其实是空的(对应 20 脚封装才有),这与论坛说法一致,但与您的问题(P3.6/P3.7)无关,是我引用时搞混了对象。


那么 P3.6/P3.7 切换失败的原因,需要重新排查

既然引脚确实存在,P_SW1 设置 0x40(S1_S[1:0]=01)也符合《功能脚切换》章节定义,那问题就落在引脚被复用功能干扰或软件配置上。P3.6/P3.7 的复用功能较多:

  • P3.6:INT2、RxD_2、CMP-、ADC14、TK14
  • P3.7:INT3、TxD_2、CMP+、TK15

请重点排查以下几点:

  1. 比较器(CMP)是否被使能:P3.6/P3.7 分别是比较器的 CMP-/CMP+ 输入脚。若 CMPEN 等比较器使能位被打开,可能占用这两个脚。
  2. I/O 模式配置:TxD_2(P3.7)需为输出,若配成高阻输入则发不出;RxD_2(P3.6)若配成推挽输出也可能影响接收。建议接收脚配为准双向或高阻输入。
  3. 外部电路:您提到"串口收发是基于 DMA 传送的",请确认 P3.6/P3.7 上没有接其他外设拉死电平。
  4. 中断/ADC/TK 未误开:确认 ADC14(P3.6)、TK14/TK15、INT2/INT3 等未被意外使能。

为了帮您精确定位,能否提供以下信息:

  • 您实际使用的具体封装(TSSOP20 / SOP16 / QFN20)?
  • 您对 P3M0/P3M1(P3.6、P3.7 的 I/O 模式)是如何配置的?
  • P_SW1 除了 S1_S,SPI_S[1:0] 是否也有设置?(P_SW1 的低两位是 SPI 切换,若 SPI 也切到同一组引脚可能冲突)

这样我可以对照手册帮您逐条确认。


🔍 搜索 "TSSOP20 SOP16 QFN20"

📌 相关论坛讨论

  1. STC8H1K17T,串口1定位到P36/P3.7失败!
  2. 较新型号的STC单片机都没有P1.2,为什么呢?
  3. STC8G1K08-38I-SOP16/TSSOP20/QFN20 STC8G1K17-38I-SOP16/TSSOP20/QFN20 有 T0/T1/T2

⏱️ 查找用时 2.8s | 总回答用时 7.1s

回复

使用道具 举报 送花

已绑定手机

872

主题

1万

回帖

2万

积分

管理员

积分
25428
发表于 2026-10-11 09:38:23 | 显示全部楼层
STC8H1K17T, TSSOP20封装,帮产生一个完整的
DMA支持的串口1收发程序,主频 22.1184MH,
【P3.6接收/P3.7发送】

截图202610110938122871.jpg

回复

使用道具 举报 送花

已绑定手机

872

主题

1万

回帖

2万

积分

管理员

积分
25428
发表于 2026-10-11 09:38:51 | 显示全部楼层

我已获取到全部所需信息。现在为您编写完整的 DMA 串口1收发程序。


说明

  • 芯片:STC8H1K17T(TSSOP20 封装)
  • 主频:22.1184MHz
  • 串口1:RxD = P3.6,TxD = P3.7(通过 P_SW1 的 S1_S[1:0]=01 切换)
  • 功能:DMA 接收 + DMA 发送。PC 发来的数据由 DMA 自动存入缓冲区(接收超时判断),超时后把收到的数据通过 DMA 自动回发。
  • 波特率:115200(用定时器1模式0做波特率发生器,1T 模式)

说明:STC8H 系列是 8 位机,使用 Keil C51 编译。以下为单文件完整程序。


/************************************************************
 * 文件名  : UART1_DMA_STC8H1K17T.c
 * 芯片    : STC8H1K17T (TSSOP20封装)
 * 主频    : 22.1184MHz
 * 功能    : 串口1 DMA 全双工收发
 *           RxD = P3.6   TxD = P3.7  (P_SW1: S1_S[1:0] = 01)
 *           波特率 115200(定时器1模式0, 1T)
 * 操作说明:
 *   1). 用 STC-ISP/AiCube-ISP 下载,IRC频率选 22.1184MHz
 *   2). 打开串口助手,波特率 115200,8-N-1
 *   3). 向单片机发送任意数据(少于DMA_AMT_LEN字节)
 *   4). 串口1接收中断做超时判断,超时5ms后判定一帧结束
 *   5). 主循环中把收到的数据用 DMA 原样发回
 ************************************************************/
#include "stc8h.h"
#include "intrins.h"

#define MAIN_Fosc       22118400UL      // 主频 22.1184MHz
#define Baudrate1       115200UL        // 波特率

#define DMA_AMT_LEN     16              // DMA 接收/发送总字节数:实际为 (n+1)=16 字节

// DMA 收发缓冲区(放在 XRAM,DMA 要求地址为扩展 RAM 空间)
unsigned char xdata DMABuffer[DMA_AMT_LEN];

// 全局标志
unsigned char Rx_cnt = 0;               // 接收字节计数(用于超时判断)
unsigned char RX1_TimeOut = 0;          // 接收超时计数
bit B_1ms = 0;                          // 1ms 标志
bit DMARxFlag = 0;                      // DMA 接收完成标志
bit DMATxFlag = 0;                      // DMA 发送完成标志
bit B_DoSend = 0;                       // 主循环需要发送的标志

/************************************************************
 * 函数名 : Uart1_Init
 * 功能   : 串口1初始化, 定时器1做波特率发生器, 定位 RxD=P3.6/TxD=P3.7
 ************************************************************/
void Uart1_Init(void)
{
    // ---- 串口1功能脚切换: P_SW1 的 S1_S[1:0]=01 => P3.6/P3.7 ----
    P_SW1 &= 0x3F;                      // 清零 b7b6, 保留 SPI_S
    P_SW1 |= 0x40;                      // S1_S[1:0]=01 => RxD=P3.6, TxD=P3.7

    // ---- P3.6 配置为准双向口(接收), P3.7 配置为推挽输出(发送) ----
    P3M1 &= ~0x80;  P3M0 |=  0x80;      // P3.7: 推挽输出 (M1=0,M0=1)
    P3M1 &= ~0x40;  P3M0 &= ~0x40;      // P3.6: 准双向口 (M1=0,M0=0)

    // ---- 波特率: 使用定时器1, 模式0(16位自动重装), 1T模式 ----
    TR1 = 0;                            // 先关闭定时器1
    AUXR &= ~0x01;                      // S1ST2=0: 串口1选择定时器1做波特率发生器
    AUXR |=  (1 << 6);                  // T1x12=1: 定时器1为1T模式

    TMOD &= ~(1 << 6);                  // 定时器1设为定时器模式
    TMOD &= ~0x30;                      // 定时器1为16位自动重装载模式
    TH1 = (unsigned char)((65536UL - (MAIN_Fosc / 4) / Baudrate1) / 256);
    TL1 = (unsigned char)((65536UL - (MAIN_Fosc / 4) / Baudrate1) % 256);
    ET1 = 0;                            // 禁止定时器1中断
    TR1 = 1;                            // 启动定时器1

    // ---- 串口1: 模式1(8位数据,可变波特率), 允许接收 ----
    SCON = 0x50;                        // SM0 SM1 = 01, REN = 1
    PCON &= 0x7F;                       // SMOD = 0: 波特率不倍速

    ES = 1;                             // 允许串口1中断(用于超时判断)
}

/************************************************************
 * 函数名 : Timer0_Init
 * 功能   : 定时器0初始化, 1ms 定时, 用于接收超时判断
 ************************************************************/
void Timer0_Init(void)
{
    AUXR |=  (1 << 7);                  // T0x12=1: 定时器0为1T模式
    TMOD &= ~0x03;                      // 定时器0为16位自动重装载模式
    TL0 = (unsigned char)(65536UL - (MAIN_Fosc / 1000));    // 1ms
    TH0 = (unsigned char)((65536UL - (MAIN_Fosc / 1000)) / 256);
    TF0 = 0;                            // 清除TF0标志
    TR0 = 1;                            // 启动定时器0
    ET0 = 1;                            // 允许定时器0中断
}

/************************************************************
 * 函数名 : DMA_Config
 * 功能   : 串口1 DMA 收发配置
 ************************************************************/
void DMA_Config(void)
{
    // ---- UR1T DMA 发送配置 ----
    DMA_UR1T_CFG = 0x80;                // bit7=1: 使能 UR1T_DMA 中断
    DMA_UR1T_STA = 0x00;                // 清除发送状态标志
    DMA_UR1T_AMT = DMA_AMT_LEN - 1;     // 传输总字节数: n+1
    DMA_UR1T_TXA = DMABuffer;           // 设置发送源地址
    DMA_UR1T_CR  = 0xC0;                // bit7=1:使能 UR1T_DMA; bit6=1:开始自动发送

    // ---- UR1R DMA 接收配置 ----
    DMA_UR1R_CFG = 0x80;                // bit7=1: 使能 UR1R_DMA 中断
    DMA_UR1R_STA = 0x00;                // 清除接收状态标志
    DMA_UR1R_AMT = DMA_AMT_LEN - 1;     // 传输总字节数: n+1
    DMA_UR1R_RXA = DMABuffer;           // 设置接收目标地址
    DMA_UR1R_CR  = 0xA1;                // bit7=1:使能; bit5=1:开始接收; bit0=1:清除FIFO
}

/************************************************************
 * 函数名 : UART1_Isr
 * 中断号 : 4
 * 功能   : 串口1中断, 做接收超时判断
 ************************************************************/
void UART1_Isr(void) interrupt 4
{
    if (RI)
    {
        RI = 0;                         // 清除RI位
        Rx_cnt++;                       // 接收计数
        if (Rx_cnt >= DMA_AMT_LEN) Rx_cnt = 0;
        RX1_TimeOut = 5;                // 5ms 没收到新数据, 判定一帧接收完毕
    }
    if (TI)
    {
        TI = 0;                         // 清除TI位
    }
}

/************************************************************
 * 函数名 : Timer0_Isr
 * 中断号 : 1
 * 功能   : 定时器0中断, 1ms 标志
 ************************************************************/
void Timer0_Isr(void) interrupt 1
{
    B_1ms = 1;                          // 1ms 标志
}

/************************************************************
 * 函数名 : UART1_DMA_Isr
 * 中断号 : 13
 * 功能   : 串口1 DMA 中断
 ************************************************************/
void UART1_DMA_Isr(void) interrupt 13
{
    if (DMA_UR1T_STA & 0x01)            // 发送完成
    {
        DMA_UR1T_STA &= ~0x01;
        DMATxFlag = 1;
    }
    if (DMA_UR1T_STA & 0x04)            // 数据覆盖
    {
        DMA_UR1T_STA &= ~0x04;
    }
    if (DMA_UR1R_STA & 0x01)            // 接收完成
    {
        DMA_UR1R_STA &= ~0x01;
        DMARxFlag = 1;
    }
    if (DMA_UR1R_STA & 0x02)            // 数据丢弃
    {
        DMA_UR1R_STA &= ~0x02;
    }
}

/************************************************************
 * 函数名 : main
 * 功能   : 主函数
 ************************************************************/
void main(void)
{
    unsigned char i;

    // ---- 初始化 ----
    P_SW2 |= 0x80;                      // 允许访问 XFR 扩展寄存器

    Uart1_Init();                       // 串口1初始化
    Timer0_Init();                      // 定时器0初始化(1ms)
    DMA_Config();                       // DMA 收发配置

    EA = 1;                             // 打开总中断

    while (1)
    {
        // ---- 1ms 定时处理 ----
        if (B_1ms)
        {
            B_1ms = 0;
            if (RX1_TimeOut)
            {
                RX1_TimeOut--;
                if (RX1_TimeOut == 0)   // 超时, 一帧接收完毕
                {
                    B_DoSend = 1;       // 通知主循环发送
                }
            }
        }

        // ---- 接收超时后, 用 DMA 把收到的数据原样发回 ----
        if (B_DoSend)
        {
            B_DoSend = 0;

            // 停止并重新配置发送 DMA
            DMA_UR1T_CR  = 0x00;                    // 关闭并停止 UR1T_DMA
            DMA_UR1T_STA = 0x00;                    // 清标志
            DMA_UR1T_AMT = DMA_AMT_LEN - 1;         // 发送字节数
            DMA_UR1T_TXA = DMABuffer;               // 发送源地址
            DMA_UR1T_CR  = 0xC0;                    // 使能 + 触发发送

            // 重新启动接收 DMA, 准备下一帧
            DMA_UR1R_CR  = 0x00;                    // 关闭并停止 UR1R_DMA
            DMA_UR1R_STA = 0x00;                    // 清标志
            DMA_UR1R_AMT = DMA_AMT_LEN - 1;
            DMA_UR1R_RXA = DMABuffer;
            DMA_UR1R_CR  = 0xA1;                    // 使能 + 开始接收 + 清FIFO

            Rx_cnt = 0;
        }
    }
}

关键点说明

  1. 引脚切换:P_SW1 的 S1_S[1:0] 位于 B7、B6。P_SW1 &= 0x3F 先清零 b7b6,再 |= 0x40 得到 01,即 RxD=P3.6、TxD=P3.7。这与《功能脚切换》章节的 S1_S[1:0]=01 定义一致。

  2. I/O 模式:P3M0/P3M1 中 P3.7 对应 B7、P3.6 对应 B6。

    • P3.7 作发送:推挽输出(M1=0, M0=1)
    • P3.6 作接收:准双向口(M1=0, M0=0)
  3. DMA 总字节数:DMA_UR1T_AMT / DMA_UR1R_AMT 写入的是 n-1,实际传输 n 字节(手册注明"实际字节数为 DMA_AMT+1")。

  4. DMA 中断号:串口1的 DMA 中断号为 13(与手册例程一致)。

  5. XFR 访问:DMA 相关寄存器(DMA_UR1T_xxx 等)属于扩展寄存器,必须先执行 P_SW2 |= 0x80 打开 EAXFR。


如果您希望改成 接收满固定字节数就回发(不用超时判断),或需要修改波特率,告诉我即可。另外请确认一下您实际使用的波特率,上面的程序默认是 115200,如需 9600 等其它值我可以帮您调整重装值。


🔍 搜索 "STC8H1K17T TSSOP20 串口1 DMA 收发程序"

📌 相关论坛讨论

  1. STC8H1K17T,串口1定位到P36/P3.7失败!
  2. 【AI助手】@AiCube-ISP-V6.97中,【自动生成程序】+【查错高手】
  3. 8H系列,串口1打印问题。

⏱️ 查找用时 8.7s | 总回答用时 20.3s

回复

使用道具 举报 送花

已绑定手机

872

主题

1万

回帖

2万

积分

管理员

积分
25428
发表于 2026-10-11 09:43:47 | 显示全部楼层

I/O口要初始化,否则 P3.6/P3.7工作在高阻输入【只能输入,不能输出】

截图202610110942457084.jpg
回复

使用道具 举报 送花

27

主题

153

回帖

901

积分

高级会员

积分
901
 楼主| 发表于 2026-10-11 10:25:57 | 显示全部楼层
1,首先表示感谢!休息日也这么快回复!
(出门买了趟菜,大神居然给说得清清楚楚,谢谢!)
2,然后表示大意已知悉。估计是用了比较器CMP+/CMP-/CMPo的原因!容我去查看下。。。

3,结果:果然,我原来的项目用了片内比较器(现在不用了)。
去掉比较器的初始化代码就OK!


回复

使用道具 举报 送花

已绑定手机

11

主题

484

回帖

1362

积分

金牌会员

积分
1362
发表于 2026-10-11 10:32:10 | 显示全部楼层
P30/P31上电默认准双向,P3.6/P3.7 上电默认高阻,需要设置为准双向且不宜复用其它功能。
回复

使用道具 举报 送花

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

本版积分规则

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

GMT+8, 2026-11-7 12:24 , Processed in 0.080496 second(s), 80 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

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