2025.01.22开始学习第16讲
一、STC8H8K64U的定时/计数器应用举例
定时器11.0592最长18s
真正的功能是在中断服务程序中实现
定时器定时量程的扩展
1.软件扩展方法
一个定时器的输出当做另一个定时器的输入。
对中断进行计数
2.硬件扩展方法
第17讲 串行通信的分类2
2025.03.10
1.STC 8H8K64U单片机集成了
4个异步串行通信接口(UART)
1个SPI通信口
1个I2C接口
1个USB接口
2.串行通信的相关概念
基本的数据通信方式有两种
通讯(数字、数据、其他的信息交换的方法)和通信的区别
并行通信--数据的各位同时传送
串行通信--数据一位一位地顺序传送(从低位开始发送),设备必须共地
RS232一般15米,最长不超过30米
RS485/9600传输距离1000米(常见的32个节点)
3.串行通信的分类
①按照通信格式的同步方式分类:异步通信、同步通信
异步通信,每一个字符都要用起始位(0)和停止位(1)作为字符开始和结束的标志,它们是以字符为单位一个个地发送和接收的。
7位数据格式串行通信传输(0-127),8位数据格式串行通信传输(0-255),大于255的数可以分成2个字节传输。
在异步数据传送中,CPU与外设之间事先必须约定好以下内容:
字符格式:双方要设定好字符的编码形式、奇偶校验形式、起始位和停止位的规定。
通信速率:通常使用波特率来表示。
表示方法 9600(bps),n(没有校验位,e偶,o奇校验),8(8个数据位),1(停止位)
同步通信,效率高,但线路复杂,适合于近距离通信。
同步传送时需要注意的是:收发双方必须使用相同的同步字符,在同步传送中要求用同步时钟来实现发送端和接收端之间的严格同步,而且对同步时钟脉冲信号的相位一致性要求非常严格。
同步字符1---同步字符2---n个数据字节---校验字节1---校验字节2
②按照数据的传送方向分类:单工(只允许数据按一个固定方向传送)、半双工(数据可以从A到B,也可以从B到A,但同一时刻只能向一个方向传送)、全双工(数据可同时在两个方向传送)
还可以分为多终端半双工通信、多终端全双工通信
4.通用异步接收器/发送器UART
UART(Universal Asynchronous Receiver/Transmitter)通用的异步接收器/发送器
姚总补充,多机通信时Tx侧加二极管
2025.03.14-3.29陆续学习
第18讲
多机通信,RXD和TXD连接注意事项
本节内容
一、STC8H8K64U单片机的串口简介
沿用15系列单片机,4个UART全双工
串口1有四种工作模式
串口2-4只有两种工作模式(UART)
串口分时复用
二、STC8H8K64U的UART(串行)接口的寄存器
SCON SBUF重点关注
单机通信选择模式1,多机通信选模式3
串口通信涉及定时器,定时器涉及中断,所以先学中断
位传送,MOV指令中出现C,位寻址中必须有C的参与
三、STC8H8K64U单片机的串口工作模式
起始位检测的重要性,起始位检测错了,后边的数据就
都有问题了。(设计了下降延传输检测器)
2025.03.30
第19讲
串口通信、多机通信
一、波特率的设定
串口1常用模式1和3,波特率可变。编程时应注意,当定时器作为波特率发生器使用时,应禁止定时器产生中断(ET1=0或ET2=0)注意此处ET1和ET2不能直接写,因为其不能按位寻址。
二、UART接口的应用举例
在编程应用中,虽然可以采用查询的方式进行通信,但是,为了进行实时任务处理,一般采用中断方式进行串行通信程序设计。
(1)串口1的编程要点
在中断服务程序中要有清除中断标志指令(将T1和R1清0)
(2)串口2的编程要点
补充:串口2在使用时,相关I/O口的设置,默认是高阻输入。
定时器中断触发原理
在 51 单片机中,定时器中断的触发流程如下:
[*]定时器配置:对定时器的工作模式、初值等进行设置。
[*]计数操作:定时器开启后,依据系统时钟频率和预分频系数开始计数。
[*]中断触发:当计数值达到最大值(溢出)时,会置位定时器溢出标志位。
[*]中断响应:若中断允许,单片机就会暂停当前程序,转而执行对应的定时器中断服务程序。
[*]中断返回:中断服务程序执行完毕后,单片机返回主程序继续执行。
简单示例
下面是一个 51 单片机定时器 0 的简单示例,该示例将定时器 0 设置为模式 1(16 位定时器),每 50ms 触发一次中断,在中断服务程序中对一个变量进行计数,计满 20 次(即 1 秒)时,翻转 P1.0 引脚的电平。
#include <reg51.h>
// 定义定时器0溢出次数计数器
unsigned char count = 0;
// 定时器0中断服务程序
void timer0_isr() interrupt 1 {
// 重新加载初值,以实现每50ms触发一次中断
TH0 = (65536 - 50000) / 256;
TL0 = (65536 - 50000) % 256;
count++;
if (count >= 20) {
// 每1秒翻转一次P1.0引脚的电平
P1 ^= 0x01;
count = 0;
}
}
void main() {
// 配置定时器0为模式1
TMOD = 0x01;
// 加载初值,以实现每50ms触发一次中断
TH0 = (65536 - 50000) / 256;
TL0 = (65536 - 50000) % 256;
// 使能定时器0中断
ET0 = 1;
// 使能全局中断
EA = 1;
// 启动定时器0
TR0 = 1;
while (1) {
// 主循环可以处理其他任务
}
}代码解释
[*]头文件包含:#include <reg51.h>包含了 51 单片机的寄存器定义。
[*]全局变量:count用于记录定时器 0 的溢出次数。
[*]中断服务程序:timer0_isr()是定时器 0 的中断服务程序,当中断触发时会执行该程序。在程序里,重新加载定时器初值,使定时器每 50ms 溢出一次;对count进行计数,计满 20 次(即 1 秒)时,翻转 P1.0 引脚的电平,并将count清零。
[*]主函数:
[*]配置定时器 0 为模式 1。
[*]加载定时器初值,让定时器每 50ms 溢出一次。
[*]使能定时器 0 中断和全局中断。
[*]启动定时器 0。
[*]进入无限循环,主循环可处理其他任务。
这个示例展示了如何使用 51 单片机的定时器 0 产生中断,并在中断服务程序中执行特定任务。
定时器 0 每 50ms 触发一次计数并非定时器本身固有的特点,而是通过对定时器进行一系列设置来实现的。下面为你详细说明在 51 单片机里如何设置以达成每 50ms 触发一次计数。
关键设置因素
1. 工作模式选择
51 单片机的定时器有多种工作模式,不同模式下定时器的计数范围和功能有所不同。以定时器 0 为例,一般选用模式 1(16 位定时器模式),因为该模式计数范围较大,能够满足较长时间间隔的定时需求。
2. 初值计算与加载
定时器的计数是从初始值开始的,当计数值达到最大值(对于 16 位定时器,最大值为 65535)时会产生溢出中断。要实现每 50ms 触发一次中断,就需要根据单片机的晶振频率来计算并加载合适的初值。
假设单片机的晶振频率为 11.0592MHz,机器周期是晶振周期的 12 倍,即机器周期
要定时 50ms,需要的机器周期数
那么定时器的初值 X=65536−N=65536−46080=19456。将这个初值拆分为高 8 位和低 8 位:
[*]高 8 位:TH0=(65536−46080)/256=76(十六进制为 0x4C)
[*]低 8 位:TL0=(65536−46080)%256=160(十六进制为 0xA0)
3. 中断使能
要让定时器溢出时能够触发中断,需要使能定时器中断和全局中断。通过设置相应的中断允许寄存器(如ET0和EA)来实现。
#include <reg51.h>
// 定时器0中断服务程序
void timer0_isr() interrupt 1 {
// 重新加载初值,以实现每50ms触发一次中断
TH0 = (65536 - 50000) / 256;
TL0 = (65536 - 50000) % 256;
// 其他中断处理代码
}
void main() {
// 配置定时器0为模式1
TMOD = 0x01;
// 加载初值,以实现每50ms触发一次中断
TH0 = (65536 - 50000) / 256;
TL0 = (65536 - 50000) % 256;
// 使能定时器0中断
ET0 = 1;
// 使能全局中断
EA = 1;
// 启动定时器0
TR0 = 1;
while (1) {
// 主循环可以处理其他任务
}
}
[*]TMOD = 0x01;:把定时器 0 设置为模式 1。
[*]TH0 = (65536 - 50000) / 256; 和 TL0 = (65536 - 50000) % 256;:计算并加载定时器 0 的初值,以实现每 50ms 触发一次中断。
[*]ET0 = 1;:使能定时器 0 中断。
[*]EA = 1;:使能全局中断。
[*]TR0 = 1;:启动定时器 0。
综上所述,定时器 0 每 50ms 触发一次计数是通过对工作模式、初值以及中断使能等方面进行设置来实现的。
程序中对定时器0赋值的50000和计算得出结果46080为什么不一样?
程序中出现赋值的 50000 和计算得出的 46080 不同,主要是因为二者在定时计算里代表的含义有差异,下面为你详细解释。
在代码里 TH0 = (65536 - 50000) / 256; 和 TL0 = (65536 - 50000) % 256; 中的 50000 是假定单片机的晶振频率为 12MHz 时计算得出的结果。
当晶振频率为 12MHz 时,机器周期
若要实现 50ms 的定时,所需的机器周期数
由于定时器 0 在模式 1 下是 16 位定时器,其计数范围是 0 - 65535。为了能在计满 50000 个机器周期后产生溢出,就要给定时器赋初值 X=65536−50000。
而 46080 是在晶振频率为 11.0592MHz 时计算得出的。此时机器周期
要实现 50ms 的定时,所需的机器周期数
同样,为了在计满约 46080 个机器周期后产生溢出,要给定时器赋初值 X=65536−46080。
总结
*50000 是晶振频率为 12MHz 时,实现 50ms 定时所需的机器周期数。
*46080 是晶振频率为 11.0592MHz 时,实现 50ms 定时所需的机器周期数。
在实际应用中,要依据所使用单片机的晶振频率来正确计算定时器的初值,这样才能确保定时的准确性。若晶振频率是 12MHz,就用 50000 来计算初值;若晶振频率是 11.0592MHz,则用 46080 来计算初值。
11.0592M晶振在串口通讯的波特率上是如何体现?如何进行相关计算
在串口通信中,11.0592MHz 晶振能很好地满足常见波特率设置且误差极小,以下为你详细介绍它在波特率上的体现以及相关计算方法。体现优势的原因
串口通信的波特率是指每秒传输的比特数。在 51 单片机中,波特率通常由定时器溢出率来决定。
11.0592MHz 晶振之所以在串口通信中表现出色,是因为它能让定时器产生的溢出率与常见的标准波特率精确匹配,进而保证数据传输的准确性。
相关计算步骤
1. 明确波特率计算公式
在 51 单片机中,当串口工作在模式 1 或模式 3 时,波特率计算公式如下:
其中,SMOD 是特殊功能寄存器 PCON 的最高位(位 7),当 SMOD = 0 时,波特率不加倍;当 SMOD = 1 时,波特率加倍。
定时器溢出率的计算公式为:
这里,fosc 是晶振频率,n 是定时器的位数(对于定时器 1 工作在模式 2,n=8),X 是定时器的初值。
2. 以 9600bps 波特率为例计算定时器初值
假设使用定时器 1 工作在模式 2(8 位自动重装模式),SMOD = 0(波特率不加倍),晶振频率 fosc=11.0592MHz,波特率为 9600bps。
3. 代码实现
以下是一个简单的 51 单片机串口初始化代码示例,设置波特率为 9600bps:
#include <reg51.h>
void UART_Init() {
// 设置定时器 1 工作在模式 2
TMOD |= 0x20;
// 加载定时器初值
TH1 = 0xFD;
TL1 = 0xFD;
// 使能定时器 1
TR1 = 1;
// 设置串口工作在模式 1
SCON = 0x50;
// 波特率不加倍
PCON &= 0x7F;
}
void main() {
UART_Init();
while (1) {
// 主循环可进行其他操作
}
}总结
通过上述计算和代码示例可知,使用 11.0592MHz 晶振能够方便地计算出合适的定时器初值,实现常见的标准波特率,保证串口通信的准确性和稳定性。在实际应用中,可根据具体的波特率要求,按照上述步骤计算定时器初值并进行相应的设置。
2025.06.04学习了何宾老师 《STC 32G12K128》视频中”第四十七集 定时器与计数器原理和应用-模块功能、工作模式、寄存器组“
通过何宾老师的详细讲解明白了定时器/计数器的工作模式中速度为1T和12T时的计算公式背后的原理及容易混淆的一些概念问题,还有就是影子寄存器的概念。