上面是查询方式发送的代码,让AI助手重写了一个中断方式的,一字未改同样正确运行。
、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
中断方式改写已完成,依据为手册「中断系统」章(UART1 向量 0023H/中断号 4/使能位 ES 在 IE.B4;UART2 向量 0043H/中断号 8/使能位 ES2 在 IE2.B0)和「串口通信」章(S2TI 在 S2CON.B1、S2RI 在 S2CON.B0,响应后必须软件清零)。
思路:改成环形缓冲区 + 中断发送。要发的字符串先放进缓冲区,启动第一个字节发送后就立刻返回,后续字节全在中断里逐字节发出,主循环不再阻塞等待。
/* ==================================================================
* STC8H8K64U 双串口定时发送例程(中断发送方式)
* ------------------------------------------------------------------
* 硬件连接:
* 串口1:TxD1 = P3.1 RxD1 = P3.0
* 串口2:TxD2 = P1.1 RxD2 = P1.0 (STC8H8K64U 默认脚位)
* 若需要改用其它脚位,请通过 P_SW1 / P_SW2 切换
* (本程序用默认脚位,因此不对 P_SW1/P_SW2 做设置)。
*
* 功能说明:
* 系统时钟 11.0592MHz,串口1、串口2 均为 115200,8,N,1
* 每隔 1 秒,串口1 发送 "this is Uart1\r\n"
* 串口2 发送 "this is Uart2\r\n"
*
* 发送方式为“中断 + 环形缓冲区”:
* Uart1_SendString / Uart2_SendString 只负责把数据放进缓冲区,
* 并启动第一个字节发送,然后立即返回,不阻塞主循环;
* 后续每个字节在串口中断里自动接着发出。
*
* 编译环境:Keil C51,选择 STC8H 系列,头文件 stc8h.h
* 下载设置:STC-ISP 中选择内部 IRC 频率 11.0592MHz
* ================================================================== */
#include "stc8h.h"
#include "intrins.h"
#define FOSC 11059200UL /* 系统工作频率 11.0592MHz */
#define BAUDRATE 115200UL /* 串口波特率 */
/* 串口1:定时器1 模式2(8位自动重载)做波特率发生器,1T 模式
重载值 = 256 - (SYSclk / 32) / 波特率
+16 是为了让 Keil 编译器自动实现四舍五入 */
#define BRT1 (256 - (FOSC / BAUDRATE + 16) / 32)
/* 串口2:定时器2 做波特率发生器,1T 模式
重载值 = 65536 - SYSclk / 4 / 波特率
+2 是为了让 Keil 编译器自动实现四舍五入 */
#define BRT2 (65536 - (FOSC / BAUDRATE + 2) / 4)
#define UART1_BUF_LEN 32 /* 串口1 发送缓冲区长度,必须是 2 的幂 */
#define UART2_BUF_LEN 32 /* 串口2 发送缓冲区长度,必须是 2 的幂 */
/* ---------------- 串口1 发送缓冲区 ---------------- */
unsigned char xdata uart1_tx_buf[UART1_BUF_LEN];
unsigned char uart1_tx_rptr; /* 写入位置(主循环使用) */
unsigned char uart1_tx_wptr; /* 读取位置(中断使用) */
bit uart1_busy; /* 串口1 正在发送标志 */
/* ---------------- 串口2 发送缓冲区 ---------------- */
unsigned char xdata uart2_tx_buf[UART2_BUF_LEN];
unsigned char uart2_tx_rptr; /* 写入位置(主循环使用) */
unsigned char uart2_tx_wptr; /* 读取位置(中断使用) */
bit uart2_busy; /* 串口2 正在发送标志 */
unsigned int ms_cnt; /* 毫秒计数,用于 1 秒定时 */
bit time_1s_flag; /* 1 秒到达标志 */
/* ---------------- 串口1 初始化(定时器1 模式2,开中断) ---------------- */
void Uart1_Init(void)
{
SCON = 0x50; /* 模式1,8位可变波特率,允许接收 REN=1 */
TMOD &= 0x0F; /* 清掉定时器1的配置位 */
TMOD |= 0x20; /* 定时器1 工作在模式2,8位自动重装载 */
TL1 = BRT1; /* 设置定时器1的重载值 */
TH1 = BRT1; /* 模式2下 TH1 为重载寄存器 */
TR1 = 1; /* 启动定时器1 */
AUXR &= ~0x01; /* S1ST2 = 0,串口1 选择定时器1做波特率发生器 */
AUXR |= 0x40; /* T1x12 = 1,定时器1 工作在 1T 模式 */
uart1_tx_rptr = 0;
uart1_tx_wptr = 0;
uart1_busy = 0;
ES = 1; /* 允许串口1中断(IE.B4) */
}
/* ---------------- 串口2 初始化(定时器2,开中断) ---------------- */
void Uart2_Init(void)
{
S2CON = 0x50; /* S2SM0=0 模式0(8位可变波特率),S2REN=1 允许接收 */
T2L = (unsigned char)BRT2; /* 定时器2 重载值低字节 */
T2H = (unsigned char)(BRT2 >> 8); /* 定时器2 重载值高字节 */
AUXR |= 0x04; /* T2x12 = 1,定时器2 工作在 1T 模式 */
AUXR &= ~0x08; /* T2_C/T = 0,定时器2 用作定时器 */
AUXR |= 0x10; /* T2R = 1,启动定时器2 */
uart2_tx_rptr = 0;
uart2_tx_wptr = 0;
uart2_busy = 0;
IE2 |= 0x01; /* ES2 = 1,允许串口2中断(IE2.B0) */
}
/* ---------------- 串口1 发送字符串(只入缓冲区,不阻塞) ---------------- */
void Uart1_SendString(unsigned char *str)
{
while (*str != '\0')
{
uart1_tx_buf[uart1_tx_rptr] = *str++;
uart1_tx_rptr = (uart1_tx_rptr + 1) & (UART1_BUF_LEN - 1);
}
/* 若当前空闲,则启动第一个字节的发送,之后由中断接力 */
if (!uart1_busy)
{
uart1_busy = 1;
SBUF = uart1_tx_buf[uart1_tx_wptr];
uart1_tx_wptr = (uart1_tx_wptr + 1) & (UART1_BUF_LEN - 1);
}
}
/* ---------------- 串口2 发送字符串(只入缓冲区,不阻塞) ---------------- */
void Uart2_SendString(unsigned char *str)
{
while (*str != '\0')
{
uart2_tx_buf[uart2_tx_rptr] = *str++;
uart2_tx_rptr = (uart2_tx_rptr + 1) & (UART2_BUF_LEN - 1);
}
/* 若当前空闲,则启动第一个字节的发送,之后由中断接力 */
if (!uart2_busy)
{
uart2_busy = 1;
S2BUF = uart2_tx_buf[uart2_tx_wptr];
uart2_tx_wptr = (uart2_tx_wptr + 1) & (UART2_BUF_LEN - 1);
}
}
/* ---------------- 串口1 中断服务程序(中断号 4) ---------------- */
void Uart1_Isr(void) interrupt 4
{
if (SCON & 0x01) /* RI(B0) = 1,收到数据 */
{
SCON &= ~0x01; /* 软件清零 RI,读 SBUF 即丢弃 */
(void)SBUF;
}
if (SCON & 0x02) /* TI(B1) = 1,一个字节发送完成 */
{
SCON &= ~0x02; /* 软件清零 TI */
if (uart1_tx_wptr != uart1_tx_rptr) /* 缓冲区还有数据 */
{
SBUF = uart1_tx_buf[uart1_tx_wptr];
uart1_tx_wptr = (uart1_tx_wptr + 1) & (UART1_BUF_LEN - 1);
}
else /* 缓冲区空了,发送结束 */
{
uart1_busy = 0;
}
}
}
/* ---------------- 串口2 中断服务程序(中断号 8) ---------------- */
void Uart2_Isr(void) interrupt 8
{
if (S2CON & 0x01) /* S2RI(B0) = 1,收到数据 */
{
S2CON &= ~0x01; /* 软件清零 S2RI,读 S2BUF 即丢弃 */
(void)S2BUF;
}
if (S2CON & 0x02) /* S2TI(B1) = 1,一个字节发送完成 */
{
S2CON &= ~0x02; /* 软件清零 S2TI */
if (uart2_tx_wptr != uart2_tx_rptr) /* 缓冲区还有数据 */
{
S2BUF = uart2_tx_buf[uart2_tx_wptr];
uart2_tx_wptr = (uart2_tx_wptr + 1) & (UART2_BUF_LEN - 1);
}
else /* 缓冲区空了,发送结束 */
{
uart2_busy = 0;
}
}
}
/* ---------------- 定时器0 初始化:1ms 中断 @11.0592MHz ---------------- */
void Timer0_Init(void)
{
AUXR |= 0x80; /* T0x12 = 1,定时器0 工作在 1T 模式 */
TMOD &= 0xF0; /* 清掉定时器0的配置位 */
TMOD |= 0x00; /* 定时器0 工作在模式0:16位自动重载 */
/* 1ms 重载值 = 65536 - FOSC / 1000 = 65536 - 11059 = 54477 = 0xD4CD */
TL0 = (unsigned char)(65536UL - FOSC / 1000UL);
TH0 = (unsigned char)((65536UL - FOSC / 1000UL) >> 8);
TF0 = 0; /* 清除中断请求标志 */
ET0 = 1; /* 允许定时器0中断 */
TR0 = 1; /* 启动定时器0 */
}
/* ---------------- 定时器0 中断服务程序(中断号 1) ---------------- */
void Timer0_Isr(void) interrupt 1
{
if (++ms_cnt >= 1000) /* 累计 1000 次 = 1 秒 */
{
ms_cnt = 0;
time_1s_flag = 1;
}
}
/* ---------------- 主函数 ---------------- */
void main(void)
{
P0M1 = 0x00; P0M0 = 0x00; /* P0 全部设为准双向口 */
P1M1 = 0x00; P1M0 = 0x00; /* P1 全部设为准双向口(含 TxD2/RxD2) */
P2M1 = 0x00; P2M0 = 0x00; /* P2 全部设为准双向口 */
P3M1 = 0x00; P3M0 = 0x00; /* P3 全部设为准双向口(含 TxD1/RxD1) */
P4M1 = 0x00; P4M0 = 0x00; /* P4 全部设为准双向口 */
P5M1 = 0x00; P5M0 = 0x00; /* P5 全部设为准双向口 */
P6M1 = 0x00; P6M0 = 0x00; /* P6 全部设为准双向口 */
P7M1 = 0x00; P7M0 = 0x00; /* P7 全部设为准双向口 */
Uart1_Init();
Uart2_Init();
Timer0_Init();
ms_cnt = 0;
time_1s_flag = 0;
EA = 1; /* 打开总中断(放在所有外设初始化之后) */
while (1)
{
if (time_1s_flag)
{
time_1s_flag = 0;
Uart1_SendString("this is Uart1\r\n"); /* 立即返回,不阻塞 */
Uart2_SendString("this is Uart2\r\n");
}
}
}
?
后面的关键点说明,论坛提示有不良信息,不让发布,所以贴个截图
