找回密码
 立即注册
查看: 343|回复: 5

请问一下STC8H单片机串口2奇校验问题

[复制链接]
  • 打卡等级:以坛为家I
  • 打卡总天数:284
  • 最近打卡:2026-04-03 10:15:37
已绑定手机

20

主题

45

回帖

1262

积分

金牌会员

积分
1262
发表于 2025-12-24 11:56:22 | 显示全部楼层 |阅读模式
调试助手打开奇校验接收就不正常 不打开就正常 无校验数据是01 0F 1E B0 6E 02 1E A9 01 01 02 23 7F 59 D2 AE  打开奇校验数据是01 C8 04 73 09 1E 6A 01 A0 FA 65 D2 FD  


/**
* 串口2初始化函数 (用于与设备通信,P1.0/P1.1)
* 配置: 波特率9600, 8位数据位, 奇校验, 1位停止位
*/
void UART2_Init(void)
{
    S2CON = 0x50;               // 9位数据模式, 允许接收, 奇校验使能
                                // 0x54: b01010100 - S2SM0=1(9位模式), S2SM2=0, S2REN=1, S2TB8=0
   
    // 设置波特率发生器(使用定时器2)
    AUXR |= 0x04;               // 定时器2时钟1T模式
    T2L = 0x8F;                 // 9600波特率定时器值
    T2H = 0xFD;                 // 9600波特率定时器值
    AUXR |= 0x10;               // 启动定时器2
   
    IE2 |= 0x01;                // 使能串口2中断
    EA = 1;                     // 开总中断
   
    P_SW2 &= ~0x03;             // UART2: RxD2(P1.0), TxD2(P1.1)
}


void UART2_SendByte(unsigned char dat)
{   
    // 计算奇校验位
    unsigned char odd_parity = calculate_odd_parity(dat);
   
    // 设置第9位校验位
    if(odd_parity) {
        S2CON |= 0x04;          // 设置S2TB8为1
    } else {
        S2CON &= ~0x04;         // 设置S2TB8为0
    }
   
    // 写入8位数据到发送缓冲区
    S2BUF = dat;
   
    // 等待发送完成
    while(!(S2CON & 0x02));     // 等待发送完成标志S2TI置位
   
    // 清除发送完成标志
    S2CON &= ~0x02;             // 清除S2TI标志
}

回复

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:284
  • 最近打卡:2026-04-03 10:15:37
已绑定手机

20

主题

45

回帖

1262

积分

金牌会员

积分
1262
发表于 2025-12-27 12:03:46 | 显示全部楼层
#include <stc8h.h>
#include <intrins.h>

typedef         unsigned char        u8;
typedef         unsigned int        u16;
typedef         unsigned long        u32;

// 系统时钟和波特率配置
#define MAIN_Fosc  24000000L          // 系统钟频率

sbit P3_2 = P3^2;
sbit P3_3 = P3^3;
sbit P3_4 = P3^4;
sbit P3_5 = P3^5;

// 音量控制命令模板 - 除了第13个字节(音量)和第16个字节(校验和)外的固定部分
const u8 CMD_TEMPLATE[14] = {0x01,0x0F,0x1E,0xB0,0x6E,0x02,0x1E,0xA9,0x01,0x01,0x02,0x23,0x00,0x59};
const u8 CMD_SUFFIX[2] = {0xD2, 0x00};  // 固定的倒数第二字节和校验和的偏移量

// 音量值和对应的校验和映射表
const u8 VOLUME_VALUES[21] = {0x01, 0x0E, 0x19, 0x26, 0x32, 0x40, 0x4D, 0x5A, 0x66, 0x73, 0x7F,
                              0x8C, 0x99, 0xA6, 0xB2, 0xC0, 0xCE, 0xD9, 0xE6, 0xF2, 0x00};
const u8 CHECKSUM_VALUES[21] = {0xD0, 0xDF, 0xC8, 0xF7, 0xE3, 0x91, 0x9C, 0x8B, 0xB7, 0xA2, 0xAE,
                                0x5D, 0x48, 0x77, 0x63, 0x11, 0x1F, 0x08, 0x37, 0x23, 0xD1};
                       
char  sm_1  []  = {0x01,0x0F,0x1E,0xB0,0x6E,0x02,0x1E,0xA9,0x01,0x01,0x02,0x23,0x01,0x59,0xD2,0xD0,};
/**
* 延时函数(毫秒级)
*/
void delay_ms(unsigned int ms)
{
    unsigned int i;
    do{
        i = MAIN_Fosc / 10000;
        while(--i);
    }while(--ms);
}

// 定时器2相关变量
u16 timer_count = 0;
u8 send_enable = 1;  // 发送使能标志
u8 receive_counter = 0;  // 接收计数器

/**
* 定时器2初始化函数 (用于100ms定时)
*/
void Timer2_Init(u16 time)
{
        AUXR |= 0x04;                        //定时器时钟1T模式
    T2H = (65536 - (MAIN_Fosc / time)) >> 8;  // 设置定时器初值,1ms中断
    T2L = (65536 - (MAIN_Fosc / time)) & 0xFF;
        AUXR |= 0x10;                        //定时器2开始计时
    IE2 = ET2;    //使能定时器中断  
    EA = 1;       // 开启总中断
}

/**
* 串口1初始化函数 (用于与电脑通信,P3.0/P3.1)
* 配置: 波特率9600, 无校验, 1位停止位
*/
void UART1_Init(u32 brt)
{   
    SCON = 0x50;                //8位数据,可变波特率
    AUXR |= 0x40;                //定时器时钟1T模式
    AUXR &= 0xFE;                //串口1选择定时器1为波特率发生器
    TMOD &= 0x0F;                //设置定时器模式
    TH1 = (u8)((65536UL - (MAIN_Fosc / 4) / brt) >> 8);
    TL1 = (u8)  65536UL - (MAIN_Fosc / 4) / brt;
    ET1 = 0;                        // 禁止Timer1中断
    TR1  = 1;                        // 运行Timer1

    SCON = (SCON & 0x3f) | (7<<6);        // 8位数据, 1位校验位, 1位起始位, 1位停止位
       
//        SCON = 0xD0;        // 9位数据, 可变波特率, 1位奇校验, 1位停止位 (模式3)
       
    ES  = 1;        //允许中断
    EA = 1;                     // 开总中断
   
    P_SW1 &= ~0xc0;                                                //UART1/USART1: RxD(P3.0), TxD(P3.1)
}



/**
* 串口1发送一个字节 (用于发送到电脑)
*/
void UART1_SendByte(unsigned char dat)
{
    SBUF = dat;                 // 写入发送数据
    while(!TI);                 // 等待发送完成(TI=1)
    TI = 0;                     // 清除TI标志位
}

/**
* 发送字符串
*/
void SendString(char *s, int num)
{
    while (num--)                  //检测字符串结束标志
    {
        UART1_SendByte(*s++);         //发送当前字符
    }
}

/**
* 发送12个0x55字节
*/
void SendBytes1()
{
    u8 i;
    for(i = 0; i < 11; i++)
    {
        UART1_SendByte(0x55);
    }
}
void SendBytes2()
{
    u8 i;
    for(i = 0; i < 11; i++)
    {
        UART1_SendByte(0x00);
    }
}
/**
* 发送指定音量等级的音频控制命令
*/
void SendVolumeCommand(u8 volume_index)
{
        u8 command[16]; u8 i;
       
    if(volume_index >= 21) return;

    // 构建命令:复制模板 + 音量值 + 固定后缀 + 校验和
    for(i = 0; i < 12; i++) {
        command[i] = CMD_TEMPLATE[i];
    }
    command[12] = VOLUME_VALUES[volume_index];      // 音量值
    command[13] = CMD_TEMPLATE[13];                 // 0x59
    command[14] = CMD_SUFFIX[0];                    // 0xD2
    command[15] = CHECKSUM_VALUES[volume_index];    // 校验和
   
    SendString((char*)command, 16);
}

/**
* 串口1中断服务函数 (接收来自设备的数据)
*/
void Uart1_Isr(void) interrupt 4
{
         u8 received_data;
    if(RI)
    {
        RI = 0;
                received_data = SBUF;  // 读取接收到的数据
               
                        // 检查是否接收到0x55
        if(received_data == 0x55)
        {
            receive_counter++;
            // 如果连续接收到10个0x55,停止发送
            if(receive_counter >= 10)
            {
                send_enable = 0;  // 停止发送
                receive_counter = 0;  // 重置计数器
            }
        }
        else
        {
            // 如果不是0x55,重置计数器
            receive_counter = 0;
        }
        
        // 将接收到的数据回传到电脑
        UART1_SendByte(received_data);
               
    }

    if(TI)
    {
        TI = 0;
    }
}

/**
* 定时器2中断服务函数
*/
void Timer2_ISR() interrupt 12
{
    static u16 ms_count = 0;
   
    timer_count++;
    ms_count++;
   
    if(ms_count >= 500 && send_enable)  // 100ms且发送使能
    {
        ms_count = 0;
        SendBytes1();  // 发送12个0x55字节
    }

}

void main(void)
{
    P_SW2 |= 0x80;  //扩展寄存器(XFR)访问使能

    P0M1 = 0x00;   P0M0 = 0x00;   //设置为准双向口
    P1M1 = 0x00;   P1M0 = 0x00;
    P2M1 = 0x00;   P2M0 = 0x00;
    P3M1 = 0x00;   P3M0 = 0x00;
    P4M1 = 0x00;   P4M0 = 0x00;
    P5M1 = 0x00;   P5M0 = 0x00;
    P6M1 = 0x00;   P6M0 = 0x00;
    P7M1 = 0x00;   P7M0 = 0x00;
   
    UART1_Init(9600);               // 初始化串口1 (与电脑通信)
    Timer2_Init(1000);                  // 初始化定时器2用于100ms定时
       
    while(1)
    {
        if(P3_2==0)
        {
            delay_ms(10);
            if(P3_2==0)
            {
                while(!P3_2);
//                SendVolumeCommand(0);  // 发送音量等级0(对应0x01)
                                SendString(sm_1,sizeof(sm_1));   
                                delay_ms(500);
                                SendBytes2();
                P20 = !P20;
            }
        }
        if(P3_3==0)
        {
            delay_ms(10);
            if(P3_3==0)
            {
                while(!P3_3);
                SendVolumeCommand(10); // 发送音量等级10(对应0x7F)
                                delay_ms(500);
                                SendBytes2();
                P21 = !P21;
            }
        }
    }
}
为什么我这个串口助手数据发送正常 程序就不行是配置有问题吗
回复

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:370
  • 最近打卡:2026-04-04 12:33:12

844

主题

1万

回帖

2万

积分

管理员

积分
22805
发表于 2025-12-24 12:14:08 | 显示全部楼层
回复

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:370
  • 最近打卡:2026-04-04 12:33:12

844

主题

1万

回帖

2万

积分

管理员

积分
22805
发表于 2025-12-24 12:16:00 | 显示全部楼层
截图202512241215489565.jpg



//本示例在Keil开发环境下请选择Intel的8058芯片型号进行编译
//若无特别说明,工作频率一般为11.0592MHz


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

typedef unsigned char BYTE;
typedef unsigned int WORD;

#define FOSC 11059200L          //系统频率
#define BAUD 115200             //串口波特率

#define NONE_PARITY     0       //无校验
#define ODD_PARITY      1       //奇校验
#define EVEN_PARITY     2       //偶校验
#define MARK_PARITY     3       //标记校验
#define SPACE_PARITY    4       //空白校验

#define PARITYBIT NONE_PARITY   //定义校验位

sfr P0M1 = 0x93;
sfr P0M0 = 0x94;
sfr P1M1 = 0x91;
sfr P1M0 = 0x92;
sfr P2M1 = 0x95;
sfr P2M0 = 0x96;
sfr P3M1 = 0xb1;
sfr P3M0 = 0xb2;
sfr P4M1 = 0xb3;
sfr P4M0 = 0xb4;
sfr P5M1 = 0xC9;
sfr P5M0 = 0xCA;
sfr P6M1 = 0xCB;
sfr P6M0 = 0xCC;
sfr P7M1 = 0xE1;
sfr P7M0 = 0xE2;

sfr AUXR  = 0x8e;               //辅助寄存器
sfr S2CON = 0x9a;               //UART2 控制寄存器
sfr S2BUF = 0x9b;               //UART2 数据寄存器
sfr T2H   = 0xd6;               //定时器2高8位
sfr T2L   = 0xd7;               //定时器2低8位
sfr IE2   = 0xaf;               //中断控制寄存器2

#define S2RI  0x01              //S2CON.0
#define S2TI  0x02              //S2CON.1
#define S2RB8 0x04              //S2CON.2
#define S2TB8 0x08              //S2CON.3

sfr P_SW2   = 0xBA;             //外设功能切换寄存器2
#define S2_S0 0x01              //P_SW2.0

bit busy;

void SendData(BYTE dat);
void SendString(char *s);

void main()
{
    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;

    P_SW2 &= ~S2_S0;            //S2_S0=0 (P1.0/RxD2, P1.1/TxD2)
//  P_SW2 |= S2_S0;             //S2_S0=1 (P4.6/RxD2_2, P4.7/TxD2_2)

#if (PARITYBIT == NONE_PARITY)
    S2CON = 0x50;               //8位可变波特率
#elif (PARITYBIT == ODD_PARITY) || (PARITYBIT == EVEN_PARITY) || (PARITYBIT == MARK_PARITY)
    S2CON = 0xda;               //9位可变波特率,校验位初始为1
#elif (PARITYBIT == SPACE_PARITY)
    S2CON = 0xd2;               //9位可变波特率,校验位初始为0
#endif

    T2L = (65536 - (FOSC/4/BAUD));   //设置波特率重装值
    T2H = (65536 - (FOSC/4/BAUD))>>8;
    AUXR = 0x14;                //T2为1T模式, 并启动定时器2
    IE2 = 0x01;                 //使能串口2中断
    EA = 1;

    SendString("STC15F2K60S2\r\nUart2 Test !\r\n");
    while(1);
}

/*----------------------------
UART2 中断服务程序
-----------------------------*/
void Uart2() interrupt 8
{
    if (S2CON & S2RI)
    {
        S2CON &= ~S2RI;         //清除S2RI位
        P0 = S2BUF;             //P0显示串口数据
        P2 = (S2CON & S2RB8);   //P2.2显示校验位
    }
    if (S2CON & S2TI)
    {
        S2CON &= ~S2TI;         //清除S2TI位
        busy = 0;               //清忙标志
    }
}

/*----------------------------
发送串口数据
----------------------------*/
void SendData(BYTE dat)
{
    while (busy);               //等待前面的数据发送完成
    ACC = dat;                  //获取校验位P (PSW.0)
    if (P)                      //根据P来设置校验位
    {
#if (PARITYBIT == ODD_PARITY)
        S2CON &= ~S2TB8;        //设置校验位为0
#elif (PARITYBIT == EVEN_PARITY)
        S2CON |= S2TB8;         //设置校验位为1
#endif
    }
    else
    {
#if (PARITYBIT == ODD_PARITY)
        S2CON |= S2TB8;         //设置校验位为1
#elif (PARITYBIT == EVEN_PARITY)
        S2CON &= ~S2TB8;        //设置校验位为0
#endif
    }
    busy = 1;
    S2BUF = ACC;                //写数据到UART2数据寄存器
}

/*----------------------------
发送字符串
----------------------------*/
void SendString(char *s)
{
    while (*s)                  //检测字符串结束标志
    {
        SendData(*s++);         //发送当前字符
    }
}


回复

使用道具 举报 送花

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

97

主题

7246

回帖

1万

积分

超级版主

积分
13798
发表于 2025-12-24 12:25:19 | 显示全部楼层
0x50不正确,改为0x90
截图202512241225057101.jpg
截图202512241224364235.jpg
回复

使用道具 举报 送花

  • 打卡等级:偶尔看看II
  • 打卡总天数:27
  • 最近打卡:2026-04-02 15:51:51

0

主题

22

回帖

132

积分

注册会员

积分
132
发表于 2026-1-20 13:49:07 | 显示全部楼层
请问一下STC32怎么设置串口奇校验位啊?手册中没发现相关寄存器
回复

使用道具 举报 送花

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

本版积分规则

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

GMT+8, 2026-4-4 16:05 , Processed in 0.109390 second(s), 70 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

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