请问一下STC8H单片机串口2奇校验问题
调试助手打开奇校验接收就不正常 不打开就正常 无校验数据是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标志
}
#include <stc8h.h>
#include <intrins.h>
typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;
// 系统时钟和波特率配置
#define MAIN_Fosc24000000L // 系统钟频率
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 = {0x01,0x0F,0x1E,0xB0,0x6E,0x02,0x1E,0xA9,0x01,0x01,0x02,0x23,0x00,0x59};
const u8 CMD_SUFFIX = {0xD2, 0x00};// 固定的倒数第二字节和校验和的偏移量
// 音量值和对应的校验和映射表
const u8 VOLUME_VALUES = {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 = {0xD0, 0xDF, 0xC8, 0xF7, 0xE3, 0x91, 0x9C, 0x8B, 0xB7, 0xA2, 0xAE,
0x5D, 0x48, 0x77, 0x63, 0x11, 0x1F, 0x08, 0x37, 0x23, 0xD1};
charsm_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; u8 i;
if(volume_index >= 21) return;
// 构建命令:复制模板 + 音量值 + 固定后缀 + 校验和
for(i = 0; i < 12; i++) {
command = CMD_TEMPLATE;
}
command = VOLUME_VALUES; // 音量值
command = CMD_TEMPLATE; // 0x59
command = CMD_SUFFIX; // 0xD2
command = CHECKSUM_VALUES; // 校验和
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;
}
}
}
}
为什么我这个串口助手数据发送正常 程序就不行是配置有问题吗
8H/8G/8C/8A系列4组串口同时通信的程序,Modbus 演示程序;可共享T2做波特率发生器 - 串行口,DMA支持的4组串口,RS232,RS485,Modbus, CRC16 国芯人工智能技术交流网站 - AI32位8051交流社区
看下这里面有没有直接使用的程序
//本示例在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 S2RI0x01 //S2CON.0
#define S2TI0x02 //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++); //发送当前字符
}
}
0x50不正确,改为0x90
请问一下STC32怎么设置串口奇校验位啊?手册中没发现相关寄存器
页:
[1]