给个实际能用的 STC8H8K64U-TSSOP20的RTC演示程序,RTC用外部晶振,USB-CDC通信和电脑对时
给个实际能用的 STC8H8K64U-TSSOP20的RTC演示程序,
RTC用外部晶振,USB-CDC通信和电脑对时
<p>好的,信息已经足够。现在我来编写完整的演示程序。</p>
<hr />
<p>以下是 <strong>STC8H8K64U-TSSOP20</strong> 的完整 RTC 演示程序,使用 <strong>外部 32.768KHz 晶振</strong> 作为 RTC 时钟源,通过 <strong>USB-CDC 虚拟串口</strong> 与电脑通信,实现时间显示和电脑对时功能。</p>
<hr />
<h2>硬件接线说明(TSSOP20)</h2>
<table>
<thead>
<tr>
<th align="center">引脚</th>
<th align="center">功能</th>
<th align="left">连接</th>
</tr>
</thead>
<tbody>
<tr>
<td align="center">Pin 13 (P3.0)</td>
<td align="center">USB D-</td>
<td align="left">接 USB 的 D-</td>
</tr>
<tr>
<td align="center">Pin 14 (P3.1)</td>
<td align="center">USB D+</td>
<td align="left">接 USB 的 D+</td>
</tr>
<tr>
<td align="center">Pin 15 (P3.2)</td>
<td align="center">INT0/下载按键</td>
<td align="left">接按键到 GND(用于 USB 下载)</td>
</tr>
<tr>
<td align="center">Pin 17 (P1.6)</td>
<td align="center">X32I</td>
<td align="left">接 32.768KHz 晶振 + 20pF 电容到 GND</td>
</tr>
<tr>
<td align="center">Pin 18 (P1.7)</td>
<td align="center">X32O</td>
<td align="left">接 32.768KHz 晶振 + 20pF 电容到 GND</td>
</tr>
<tr>
<td align="center">Pin 20 (VCC)</td>
<td align="center">电源</td>
<td align="left">3.3V / 5V</td>
</tr>
<tr>
<td align="center">Pin 10 (GND)</td>
<td align="center">地</td>
<td align="left">GND</td>
</tr>
</tbody>
</table>
<blockquote>
<p><strong>注意</strong>:TSSOP20 封装中,P1.6 和 P1.7 同时也是 X32I/X32O 功能脚,可直接外接 32.768KHz 晶振。</p>
</blockquote>
<hr />
<h2>程序代码</h2>
<h3>文件 1:main.c</h3>
<pre><code class="language-c">/*********************************************
* STC8H8K64U-TSSOP20 RTC + USB-CDC 演示程序
*
* 功能:
* 1. 使用外部 32.768KHz 晶振驱动 RTC 实时时钟
* 2. 通过 USB-CDC 虚拟串口每秒上报当前时间
* 3. 支持电脑通过串口发送时间字符串对时
*
* 对时命令格式(通过串口助手发送):
* SET 2025-01-15 12:30:45 3<CR><LF>
* 含义:SET YYYY-MM-DD HH:MM:SS W
* W = 星期(0=周日,1=周一,...,6=周六)
*
* 硬件平台:STC8H8K64U-TSSOP20
* 编译环境:Keil C51
* 主频:使用内部高速IRC(默认 24MHz,可在ISP下载时设置)
*
* 使用步骤:
* 1. 在 Keil 中新建项目,芯片选择 STC8H8K64U
* 2. 将 stc_usb_cdc_8h_data.LIB 库文件添加到项目
* 3. 将本文件及下面的文件添加到项目
* 4. 编译下载到芯片
* 5. 用 USB 线连接电脑,识别出 USB-CDC 串口
* 6. 打开串口助手(波特率任意),即可看到每秒上报的时间
*********************************************/
#include "stc8h.h"
#include "ai_usb.h"
#include "intrins.h"
#include "stdio.h"
#define MAIN_Fosc 24000000L // 主频 24MHz(根据实际ISP设置调整)
// 缓冲区定义
unsigned char rx_buffer; // USB接收缓冲区
unsigned char rx_index; // 接收索引
bit rx_complete; // 一行接收完成标志
// RTC 秒中断标志
bit B1S_Flag;
/*********************************************
* 函数声明
*********************************************/
void RTC_Config(void);
void RTC_SetTime(unsigned char year, unsigned char month, unsigned char day,
unsigned char hour, unsigned char min, unsigned char sec,
unsigned char week);
void Print_RTC_Time(void);
void Parse_Time_Command(void);
/*********************************************
* USB-CDC 初始化(由 usb_init() 完成)
* 无需额外配置
*********************************************/
/*********************************************
* RTC 配置:使用外部 32.768KHz 晶振
*********************************************/
void RTC_Config(void)
{
// 启动外部 32.768KHz 晶振
// X32KCR: ENX32K=1, GAIN32K=1(高增益,更易起振)
X32KCR = 0xC0;
// 等待外部晶振稳定
while (!(X32KCR & 0x01));
// 选择外部 32K 作为 RTC 时钟源
// RTCCFG.1 (RTCCKS) = 0:选择外部32K
RTCCFG &= ~0x02;
// 设置 RTC 初始时间(默认值:2025-01-01 00:00:00 周三)
INIYEAR = 25; // 2025年
INIMONTH= 1; // 1月
INIDAY = 1; // 1日
INIHOUR = 0; // 0时
INIMIN = 0; // 0分
INISEC = 0; // 0秒
INISSEC = 0; // 0/128秒
// INIWEEK 在 FE6FH,与 RTCWEEK 共用地址
// 通过 XFR 方式写入
*(unsigned char volatile xdata *)0xFE6F = 3;// 星期三
// 触发 RTC 初始化(将初始值装载到计数寄存器)
RTCCFG |= 0x01;
while (RTCCFG & 0x01); // 等待初始化完成
// 清中断标志
RTCIF = 0;
// 使能 RTC 秒中断
RTCIEN = 0x08; // ESECI = 1
// 启动 RTC
RTCCR = 0x01; // RUNRTC = 1
}
/*********************************************
* 设置 RTC 时间
*********************************************/
void RTC_SetTime(unsigned char year, unsigned char month, unsigned char day,
unsigned char hour, unsigned char min, unsigned char sec,
unsigned char week)
{
// 停止 RTC
RTCCR = 0x00;
// 设置初始值寄存器
INIYEAR = year;
INIMONTH= month;
INIDAY = day;
INIHOUR = hour;
INIMIN = min;
INISEC = sec;
INISSEC = 0;
*(unsigned char volatile xdata *)0xFE6F = week;// 设置星期
// 触发初始化
RTCCFG |= 0x01;
while (RTCCFG & 0x01);
// 清中断标志
RTCIF = 0;
// 重新启动 RTC
RTCCR = 0x01;
}
/*********************************************
* 通过 USB-CDC 打印当前 RTC 时间
*********************************************/
void Print_RTC_Time(void)
{
unsigned char year, month, day, hour, min, sec, week;
unsigned char buf;
// 读取 RTC 计数值
year= RTCYEAR;
month = RTCMONTH;
day = RTCDAY;
hour= RTCHOUR;
min = RTCMIN;
sec = RTCSEC;
week= *(unsigned char volatile xdata *)0xFE6F;// 读取星期
week &= 0x07;
// 格式化输出
sprintf((char *)buf, "20%02bd-%02bd-%02bd %02bd:%02bd:%02bd Week=%bd\r\n",
year, month, day, hour, min, sec, week);
// 通过 USB-CDC 发送
USB_SendData(buf, strlen((char *)buf));
}
/*********************************************
* 解析电脑发来的对时命令
* 格式:SET 2025-01-15 12:30:45 3
*********************************************/
void Parse_Time_Command(void)
{
unsigned char year, month, day, hour, min, sec, week;
unsigned char buf;
// 复制接收缓冲区到本地(避免操作中被覆盖)
memcpy(buf, rx_buffer, rx_index);
buf = '\0';
// 解析命令:SET YYYY-MM-DD HH:MM:SS W
if (sscanf((char *)buf, "SET %bd-%bd-%bd %bd:%bd:%bd %bd",
&year, &month, &day, &hour, &min, &sec, &week) == 7)
{
// 参数有效性检查
if ((year >= 0) && (year <= 99) &&
(month >= 1) && (month <= 12) &&
(day >= 1) && (day <= 31) &&
(hour <= 23) && (min <= 59) && (sec <= 59) &&
(week <= 6))
{
// 设置 RTC 时间
RTC_SetTime(year, month, day, hour, min, sec, week);
USB_SendData("Time set OK!\r\n", 15);
}
else
{
USB_SendData("Parameter error!\r\n", 18);
}
}
else
{
USB_SendData("Format: SET YY-MM-DD HH:MM:SS W\r\n", 34);
}
}
/*********************************************
* RTC 秒中断服务程序
*********************************************/
void RTC_Isr() interrupt 13
{
if (RTCIF & 0x08) // 判断是否秒中断
{
RTCIF &= ~0x08;// 清中断标志
B1S_Flag = 1; // 置秒标志
}
}
/*********************************************
* 主函数
*********************************************/
void main(void)
{
unsigned char i;
P_SW2 |= 0x80; // 使能 XFR 访问
// 设置所有 I/O 口为准双向口
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;
// 初始化 USB-CDC
usb_init();
// 配置 RTC(使用外部 32.768KHz 晶振)
RTC_Config();
// 初始化接收缓冲区
rx_index = 0;
rx_complete = 0;
// 打开总中断
EA = 1;
// 等待 USB 配置完成
while (DeviceState != DEVSTATE_CONFIGURED);
// 发送启动信息
USB_SendData("STC8H8K64U RTC + USB-CDC Demo\r\n", 33);
USB_SendData("Send: SET YY-MM-DD HH:MM:SS W to set time\r\n", 44);
while (1)
{
// ---- USB 数据接收处理(查询方式) ----
if (bUsbOutReady)
{
// 将接收到的数据逐个存入缓冲区
for (i = 0; i < OutNumber; i++)
{
if (UsbOutBuffer == '\n') // 遇到换行符,表示一行结束
{
rx_complete = 1;
}
else if (UsbOutBuffer != '\r')// 忽略回车符
{
if (rx_index < sizeof(rx_buffer) - 1)
{
rx_buffer = UsbOutBuffer;
}
}
}
// 处理完整的一行命令
if (rx_complete)
{
rx_buffer = '\0';
Parse_Time_Command();
rx_index = 0;
rx_complete = 0;
}
usb_OUT_done(); // 通知 USB 库接收下一包数据
}
// ---- RTC 秒中断处理 ----
if (B1S_Flag)
{
B1S_Flag = 0;
Print_RTC_Time(); // 每秒打印一次时间
}
}
}
</code></pre>
<h3>文件 2:硬件初始化与延时辅助(可选,如需要可添加)</h3>
<p>本程序未使用额外的延时函数,所有时序依赖 RTC 秒中断和 USB 库。如果需要在 main.c 中使用 <code>strlen</code>、<code>memcpy</code>、<code>sprintf</code> 等标准库函数,Keil C51 会自动链接对应的库,无需额外文件。</p>
<hr />
<h2>使用说明</h2>
<h3>1. 项目配置</h3>
<table>
<thead>
<tr>
<th align="left">项目</th>
<th align="left">设置</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">芯片型号</td>
<td align="left">STC8H8K64U</td>
</tr>
<tr>
<td align="left">编译工具</td>
<td align="left">Keil C51</td>
</tr>
<tr>
<td align="left">添加库文件</td>
<td align="left"><code>stc_usb_cdc_8h_data.LIB</code>(从 STC 官网 USB 库压缩包中获取)</td>
</tr>
<tr>
<td align="left">包含头文件</td>
<td align="left"><code>stc8h.h</code>、<code>ai_usb.h</code>(通过 ISP 软件的"添加型号和头文件到 Keil"自动安装)</td>
</tr>
<tr>
<td align="left">主频设置</td>
<td align="left">在 ISP 下载时选择内部 IRC 频率(建议 24MHz)</td>
</tr>
</tbody>
</table>
<h3>2. 硬件连接</h3>
<pre><code>USB 口 (电脑) ──── USB 线 ──── STC8H8K64U-TSSOP20
Pin13(P3.0/D-) ──── USB D-
Pin14(P3.1/D+) ──── USB D+
Pin17(P1.6/X32I) ── 32.768KHz ──┬── 20pF ── GND
Pin18(P1.7/X32O) ── 晶振 ────────┬── 20pF ── GND
Pin15(P3.2) ────── 按键 ──── GND (下载用)
Pin20(VCC) ─────── 3.3V/5V
Pin10(GND) ─────── GND
</code></pre>
<h3>3. 下载程序</h3>
<ol>
<li>按住 P3.2 按键(接 GND)</li>
<li>给芯片上电</li>
<li>在 ISP 软件中点击"下载/编程"</li>
<li>下载完成后,电脑会识别出一个 USB-CDC 虚拟串口</li>
</ol>
<h3>4. 串口通信</h3>
<p>打开串口助手,选择识别到的 USB-CDC 串口(波特率任意,USB-CDC 忽略波特率),即可看到:</p>
<pre><code>STC8H8K64U RTC + USB-CDC Demo
Send: SET YY-MM-DD HH:MM:SS W to set time
2025-01-01 00:00:01 Week=3
2025-01-01 00:00:02 Week=3
2025-01-01 00:00:03 Week=3
...
</code></pre>
<h3>5. 电脑对时</h3>
<p>发送命令(注意发送新行 <code>\r\n</code>):</p>
<pre><code>SET 25-06-15 14:30:00 0
</code></pre>
<p>返回:</p>
<pre><code>Time set OK!
</code></pre>
<p>之后 RTC 将从设置的时间开始运行,每秒上报。</p>
<hr />
<h2>关键寄存器说明</h2>
<table>
<thead>
<tr>
<th align="left">寄存器</th>
<th align="center">地址</th>
<th align="left">功能</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left"><strong>X32KCR</strong></td>
<td align="center">FE08H</td>
<td align="left">外部 32K 晶振控制:<code>ENX32K=1, GAIN32K=1</code> 启动高增益振荡</td>
</tr>
<tr>
<td align="left"><strong>RTCCFG</strong></td>
<td align="center">FE61H</td>
<td align="left">RTC 配置:<code>RTCCKS=0</code> 选外部晶振,<code>SETRTC=1</code> 触发初始化</td>
</tr>
<tr>
<td align="left"><strong>RTCCR</strong></td>
<td align="center">FE60H</td>
<td align="left">RTC 控制:<code>RUNRTC=1</code> 启动 RTC 计数</td>
</tr>
<tr>
<td align="left"><strong>RTCIEN</strong></td>
<td align="center">FE62H</td>
<td align="left">RTC 中断使能:<code>ESECI=1</code> 使能秒中断</td>
</tr>
<tr>
<td align="left"><strong>RTCIF</strong></td>
<td align="center">FE63H</td>
<td align="left">RTC 中断标志:<code>SECIF</code> 秒中断标志,需软件清 0</td>
</tr>
<tr>
<td align="left"><strong>INIYEAR~INISSEC</strong></td>
<td align="center">FE68H~FE6EH</td>
<td align="left">RTC 初始值设置寄存器(写)</td>
</tr>
<tr>
<td align="left"><strong>RTCYEAR~RTCSSEC</strong></td>
<td align="center">FE70H~FE76H</td>
<td align="left">RTC 当前计数值寄存器(只读)</td>
</tr>
<tr>
<td align="left"><strong>INIWEEK/RTCWEEK</strong></td>
<td align="center">FE6FH</td>
<td align="left">星期设置/读取</td>
</tr>
</tbody>
</table>
<blockquote>
<p><strong>注意</strong>:所有 RTC 相关寄存器均为 XFR(扩展特殊功能寄存器),访问前必须设置 <code>P_SW2 |= 0x80</code>(EAXFR=1)。</p>
</blockquote>
<hr />
<p>如果您在实际调试中遇到问题,欢迎提供更多信息(如 ISP 下载时设置的主频、串口助手截图等),我可以进一步协助排查。</p>
<hr />
<p><a href="https://www.stcaimcu.com/plugin.php?id=twpx_xunsearch&mod=forum&q=%E7%BB%99%E4%B8%AA%E5%AE%9E%E9%99%85%E8%83%BD%E7%94%A8%E7%9A%84%20STC8H8K64U-TSSOP20%E7%9A%84RTC%E6%BC%94%E7%A4%BA%E7%A8%8B%E5%BA%8F%20RTC%E7%94%A8%E5%A4%96%E9%83%A8%E6%99%B6%E6%8C%AF%20USB-CDC%E9%80%9A%E4%BF%A1%E5%92%8C%E7%94%B5%E8%84%91%E5%AF%B9%E6%97%B6&f=_all&m=yes&syn=yes&s=relevance&fid=0">🔍 搜索 "给个实际能用的 STC8H8K64U-TSSOP20的RTC演示程序 RTC用外部晶振 USB-CDC通信和电脑对时"</a></p>
<p><strong>📌 相关论坛讨论</strong></p>
<ol>
<li><a href="https://www.stcaimcu.com/forum.php?mod=viewthread&tid=24765&highlight=%E7%BB%99%E4%B8%AA%E5%AE%9E%E9%99%85%E8%83%BD%E7%94%A8%E7%9A%84%20STC8H8K64U-TSSOP20%E7%9A%84RTC%E6%BC%94%E7%A4%BA%E7%A8%8B%E5%BA%8F%EF%BC%8CRTC%E7%94%A8%E5%A4%96%E9%83%A8%E6%99%B6%E6%8C%AF%EF%BC%8CUSB-CDC%E9%80%9A%E4%BF%A1%E5%92%8C%E7%94%B5%E8%84%91%E5%AF%B9%E6%97%B6&page=1&extra=#pid222867">stc8H8K64U主晶振和rtc晶振不能同时存在?</a></li>
<li><a href="https://www.stcaimcu.com/forum.php?mod=viewthread&tid=5461&highlight=%E7%BB%99%E4%B8%AA%E5%AE%9E%E9%99%85%E8%83%BD%E7%94%A8%E7%9A%84%20STC8H8K64U-TSSOP20%E7%9A%84RTC%E6%BC%94%E7%A4%BA%E7%A8%8B%E5%BA%8F%EF%BC%8CRTC%E7%94%A8%E5%A4%96%E9%83%A8%E6%99%B6%E6%8C%AF%EF%BC%8CUSB-CDC%E9%80%9A%E4%BF%A1%E5%92%8C%E7%94%B5%E8%84%91%E5%AF%B9%E6%97%B6&page=1&extra=#pid39999">RTC对时</a></li>
<li><a href="https://www.stcaimcu.com/forum.php?mod=viewthread&tid=11507&highlight=%E7%BB%99%E4%B8%AA%E5%AE%9E%E9%99%85%E8%83%BD%E7%94%A8%E7%9A%84%20STC8H8K64U-TSSOP20%E7%9A%84RTC%E6%BC%94%E7%A4%BA%E7%A8%8B%E5%BA%8F%EF%BC%8CRTC%E7%94%A8%E5%A4%96%E9%83%A8%E6%99%B6%E6%8C%AF%EF%BC%8CUSB-CDC%E9%80%9A%E4%BF%A1%E5%92%8C%E7%94%B5%E8%84%91%E5%AF%B9%E6%97%B6&page=1&extra=#pid116204">AI8H1K08外部32768晶振起振不了</a></li>
</ol>
<p>⏱️ 查找用时 25.7s | 总回答用时 59.0s</p>
页:
[1]