STC89C52RC, 12MHz 时钟,串口通信, 4800波特率,T1做波特率发生器
贴如下内容到 STC 【AI助手】,help.stcaimcu.comSTC89C52RC, 12MHz 时钟,串口通信,
4800波特率,T1做波特率发生器,误差是多少,
帮产生1个收到 1个数就对这个数+1后,
再发送出去的,通用串口程序
<p>好的,手册数据已获取。下面我为您完整解答。</p>
<hr />
<h2>一、4800bps @ 12MHz 的波特率误差计算</h2>
<p>根据 STC89C52RC 手册"串行通信中波特率的设置"章节,STC89C52RC 默认工作在 <strong>12T模式</strong>(传统8051模式),定时器1方式2(8位自动重装)作为波特率发生器时:</p>
<p><strong>公式:</strong></p>
<blockquote>
<p>方式1、3波特率 = 2<sup>SMOD</sup> / 32 × (定时器/计数器1的溢出率)</p>
<p>12T模式下,定时器1溢出率 = SYSclk / </p>
</blockquote>
<p><strong>您的配置:</strong> SMOD=1(PCON|=0x80),N=0xF3=243,SYSclk=12MHz</p>
<p><strong>计算过程:</strong></p>
<pre><code>溢出率 = 12,000,000 /
= 12,000,000 / (12 × 13)
= 12,000,000 / 156
≈ 76,923.08 Hz
实际波特率 = 2^1 / 32 × 76,923.08
= 2 / 32 × 76,923.08
= 1/16 × 76,923.08
≈ 4807.69 bps
理论目标波特率 = 4800 bps
误差 = (4807.69 − 4800) / 4800 × 100%
≈ +0.16%
</code></pre>
<p><strong>结论:误差约为 +0.16%。</strong></p>
<p>这个误差值在 <strong>理论上是可接受的</strong>(串口异步通信通常要求误差 < 2%),但实际使用中仍可能出问题,原因在于:</p>
<ol>
<li><strong>12MHz 无法整数分频出 4800</strong>,0.16% 是理论计算值,实际晶振本身还有制造误差</li>
<li><strong>PC 端 USB 转串口芯片</strong>(如 CH340、PL2303)的波特率也是近似值,双方误差叠加后可能超过容限</li>
<li>手册中 <strong>4800bps 的标准推荐配置是 11.059MHz + SMOD=0 + 重装值 0xFA</strong>,12MHz 不在推荐列表中</li>
</ol>
<p><strong>建议:</strong> 如果坚持用 12MHz,改用 <strong>2400bps</strong>(SMOD=1,重装值 0xE6)误差更小,或直接换 <strong>11.0592MHz 晶振</strong>。</p>
<hr />
<h2>二、串口回显程序(收到1个数+1后发回)</h2>
<p>以下是完整的单文件 C 程序,实现 <strong>串口中断接收,收到一个字节后加1再发送回去</strong>:</p>
<pre><code class="language-c">/*****************************************************************************
* 文件名: main.c
* 描述: STC89C52RC 串口通信——收到1个数+1后发回
* 硬件连接: P3.0(RxD) — USB转串口模块的TxD
* P3.1(TxD) — USB转串口模块的RxD
* 晶振: 12.000MHz
* 波特率: 4800bps (SMOD=1, 定时器1方式2, 重装值0xF3)
* 编译环境: Keil C51
*
* 操作说明:
* 1. 用 STC-ISP 软件下载程序到单片机
* 2. 打开串口助手,波特率设为4800
* 3. 发送任意1个字节,单片机收到后+1再发回
* 4. 例如:发送 0x01 → 收到 0x02;发送 0x66 → 收到 0x67
*****************************************************************************/
#include <REGX52.h>
/* 接收缓冲区 */
volatile unsigned char rx_data; // 存放接收到的数据
volatile unsigned char rx_flag; // 接收完成标志,1=已收到新数据
/*****************************************************************************
* 函数名: UART_Init
* 功能: 串口初始化,4800bps@12.000MHz
* 参数: 无
* 返回值: 无
*****************************************************************************/
void UART_Init(void)
{
SCON = 0x50; // 方式1(8位UART),REN=1允许接收
PCON |= 0x80; // SMOD=1,波特率加倍
TMOD &= 0x0F; // 清除定时器1的模式位
TMOD |= 0x20; // 定时器1,方式2(8位自动重装)
TH1 = 0xF3; // 4800bps 重装值 (12MHz, SMOD=1)
TL1 = 0xF3;
ET1 = 0; // 禁止定时器1中断(波特率发生器不需要)
ES= 1; // 使能串口中断
EA= 1; // 开启总中断
TR1 = 1; // 启动定时器1
}
/*****************************************************************************
* 函数名: UART_SendByte
* 功能: 串口发送1个字节(查询方式)
* 参数: dat — 要发送的数据
* 返回值: 无
*****************************************************************************/
void UART_SendByte(unsigned char dat)
{
SBUF = dat; // 将数据写入发送缓冲器,启动发送
while (TI == 0); // 等待发送完成(TI被硬件置1)
TI = 0; // 软件清除TI标志
}
/*****************************************************************************
* 函数名: UART_ISR
* 功能: 串口中断服务函数
* 说明: 收到数据后存入rx_data,置位rx_flag
* 中断服务程序尽量简洁,数据处理放在主循环中
*****************************************************************************/
void UART_ISR(void) interrupt 4
{
if (RI == 1) // 接收中断
{
RI = 0; // 清除接收中断标志
rx_data = SBUF; // 读取接收到的数据
rx_flag = 1; // 置位接收标志
}
/* TI发送中断未使用,因为发送采用查询方式 */
}
/*****************************************************************************
* 函数名: main
* 功能: 主函数,初始化串口后循环处理接收数据
* 参数: 无
* 返回值: 无
*****************************************************************************/
void main(void)
{
unsigned char temp;
rx_flag = 0; // 初始化接收标志
UART_Init(); // 初始化串口
while (1)
{
if (rx_flag == 1) // 检查是否收到新数据
{
rx_flag = 0; // 清除标志
temp = rx_data; // 读取收到的数据
temp = temp + 1;// 数据+1
UART_SendByte(temp);// 发送回去
}
}
}
</code></pre>
<h3>程序说明</h3>
<table>
<thead>
<tr>
<th align="left">项目</th>
<th align="left">说明</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left"><strong>波特率</strong></td>
<td align="left">4800bps @ 12.000MHz,SMOD=1,重装值 0xF3</td>
</tr>
<tr>
<td align="left"><strong>接收方式</strong></td>
<td align="left"><strong>中断接收</strong>,不占用CPU轮询</td>
</tr>
<tr>
<td align="left"><strong>发送方式</strong></td>
<td align="left"><strong>查询发送</strong>,简单可靠</td>
</tr>
<tr>
<td align="left"><strong>回显逻辑</strong></td>
<td align="left">收到1字节 → 该字节+1 → 发回</td>
</tr>
<tr>
<td align="left"><strong>中断服务</strong></td>
<td align="left">仅做最简操作(读SBUF、清标志),数据处理在主循环中完成</td>
</tr>
</tbody>
</table>
<h3>测试方法</h3>
<ol>
<li>用 <strong>STC-ISP 下载软件</strong> 将程序烧录到 STC89C52RC</li>
<li>打开串口助手,设置:<strong>波特率 4800</strong>,数据位 8,停止位 1,无校验</li>
<li>发送 <strong>0x01</strong> → 应收到 <strong>0x02</strong></li>
<li>发送 <strong>0x66</strong> → 应收到 <strong>0x67</strong></li>
<li>发送 <strong>0xFF</strong> → 应收到 <strong>0x00</strong>(0xFF+1=0x100,溢出后为0x00)</li>
</ol>
<h3>如果仍然只能收到 0x00</h3>
<p>请检查以下两点:</p>
<ol>
<li><strong>晶振频率</strong>:确认板子上是 12.000MHz 还是 11.0592MHz?如果是 11.0592MHz,请将重装值改为 <strong>0xFA</strong>,并将 <code>PCON |= 0x80;</code> 改为 <code>PCON &= 0x7F;</code>(SMOD=0)</li>
<li><strong>串口助手波特率</strong>:确认串口助手的波特率设置与单片机一致(4800)</li>
<li><strong>接线</strong>:确认 P3.0(RxD) 接 USB转串口的 TxD,P3.1(TxD) 接 RxD,<strong>交叉连接</strong></li>
</ol>
<hr />
<p><a href="https://www.stcaimcu.com/plugin.php?id=twpx_xunsearch&mod=forum&q=STC89C52RC%2012MHz%20%E6%97%B6%E9%92%9F%20%E4%B8%B2%E5%8F%A3%E9%80%9A%E4%BF%A1&f=_all&m=yes&syn=yes&s=relevance&fid=0">🔍 搜索 "STC89C52RC 12MHz 时钟 串口通信"</a></p>
<p>⏱️ 查找用时 3.1s | 总回答用时 21.3s</p>
页:
[1]