HRTOS 4.0 驱动库:05_Control 控制设备驱动——PWM与继电器驱动开发
在 51 单片机、8051 嵌入式系统开发中,除了传感器和显示设备之外,PWM 输出、继电器等控制设备同样是非常常见的硬件资源。
HRTOS 4.0 在 Driver Library 中提供了独立的 05_Control 控制设备驱动模块,目前主要包含 PWM 驱动和继电器驱动,用于实现对外部执行设备的控制。
本模块通过统一的驱动接口向应用程序提供控制功能,使 51 单片机应用开发可以更加方便地调用底层硬件资源。
本文主要介绍 HRTOS 4.0 05_Control 模块的组成、硬件接口、PWM 驱动、继电器驱动、API 接口以及实际使用方法。
一、HRTOS 4.0 05_Control 模块概述
05_Control 是 HRTOS Driver Library 中面向控制设备的驱动模块。
模块主要提供:
-
PWM 脉宽调制输出
-
PWM 占空比设置与读取
-
PWM 启动与停止
-
继电器初始化
-
继电器开启与关闭
-
继电器状态设置与读取
公共头文件:
#include "HRTOS_Control.h"
模块中的驱动函数统一使用 drv_ 前缀命名,例如:
drv_pwm_init();
drv_pwm_set_duty(50);
drv_relay_init();
drv_relay_on();
所有驱动实现依赖 HRTOS 硬件抽象层:
#include "hrtos_hal.h"
这样可以将具体硬件寄存器操作与上层应用调用进行一定程度的隔离。
支持的控制设备
| 设备 | 功能 | 主要硬件 |
|---|---|---|
| PWM | PWM 波形输出、占空比控制 | PCA |
| Relay | 继电器开启、关闭、状态控制 | GPIO |
其中 PWM 驱动主要面向 STC12C5A60S2 等支持 PCA/PWM 的 51 单片机。
二、PWM 驱动
2.1 PWM 功能简介
PWM(Pulse Width Modulation,脉宽调制)是 51 单片机控制系统中非常重要的一种输出方式。
HRTOS 4.0 的 PWM 驱动基于 STC12C5A60S2 的 PCA(Programmable Counter Array,可编程计数器阵列) 模块实现。
应用程序不需要直接操作 PCA 的多个特殊功能寄存器,而是可以直接使用驱动库提供的 API 设置 PWM。
主要功能包括:
-
初始化 PCA PWM
-
设置 PWM 占空比
-
获取当前 PWM 占空比
-
启动 PWM
-
停止 PWM
例如:
drv_pwm_init();
drv_pwm_set_duty(50);
即可完成 PWM 初始化和 50% 占空比设置。
2.2 PWM 文件组成
PWM 驱动目录:
PWM/
├── pwm_init.c
├── pwm_set_duty.c
├── pwm_get_duty.c
├── pwm_start.c
└── pwm_stop.c
各文件分别对应 PWM 的不同功能:
-
pwm_init.c:PWM 初始化 -
pwm_set_duty.c:设置占空比 -
pwm_get_duty.c:读取占空比 -
pwm_start.c:启动 PWM -
pwm_stop.c:停止 PWM
这种按照功能拆分驱动源文件的方式,可以使驱动模块的结构更加清晰。
三、PWM 硬件配置
PWM 输出引脚及相关寄存器配置定义在:
HRTOS_Control.h
相关特殊功能寄存器包括:
sfr AUXR1 = 0xA2;
sfr P1M1 = 0x91;
sfr P1M0 = 0x92;
默认情况下,PWM 输出使用:
P1.3(PCA0/PWM0)
相关 PCA 寄存器包括:
| 寄存器 | 地址 | 功能 |
|---|---|---|
CCON | 0xD8 | PCA 控制寄存器 |
CMOD | 0xD9 | PCA 工作模式寄存器 |
CCAPM0 | 0xDA | PCA 模块 0 模式寄存器 |
CL | 0xE9 | PCA 计数器低 8 位 |
CH | 0xF9 | PCA 计数器高 8 位 |
CCAP0L | 0xEA | PCA 模块 0比较寄存器低 8 位 |
CCAP0H | 0xFA | PCA 模块 0比较寄存器高 8 位 |
CR | CCON.6 | PCA 运行控制位 |
因此,这个 PWM 驱动实际上是对 STC12C5A60S2 内部 PCA 硬件资源的一层驱动封装。
四、PWM 工作方式
HRTOS 4.0 PWM 驱动使用:
-
PCA 模块 0
-
8 位 PWM 模式
-
PCA 时钟:FOSC/2
-
初始化后自动启动 PCA
PWM 的用户接口采用更加直观的百分比方式。
0 → 0%
50 → 50%
100 → 100%
而底层硬件使用 8 位数值:
0 ~ 255
驱动内部首先进行占空比转换:
pwm_value = (duty * 255) / 100;
随后根据当前 PWM 输出逻辑进行反转:
CCAP0H/L = 255 - pwm_value
因此:
CCAP0H/L = 0x00 → 100%
CCAP0H/L = 0xFF → 0%
也就是说,当前 PWM 驱动采用的是反转输出逻辑。
这一点在实际使用时需要特别注意。
五、PWM API
5.1 drv_pwm_init()
函数原型:
void drv_pwm_init(void);
功能:
初始化 PCA PWM 模块。
初始化后:
-
PCA 配置为 8 位 PWM
-
PCA 时钟为 FOSC/2
-
初始占空比为 0%
-
PCA 自动启动
示例:
#include "HRTOS_Control.h"
void main(void)
{
drv_pwm_init();
// PWM 已初始化并启动
}
5.2 drv_pwm_set_duty()
函数原型:
void drv_pwm_set_duty(u8 duty);
用于设置 PWM 占空比。
参数:
duty = 0 ~ 100
例如:
drv_pwm_set_duty(50);
表示设置 50% 占空比。
也可以:
drv_pwm_set_duty(75);
设置为 75%。
如果输入参数超过 100,驱动会自动限制为 100。
占空比设置会实时生效,不需要重新初始化 PWM。
5.3 drv_pwm_get_duty()
函数原型:
u8 drv_pwm_get_duty(void);
用于获取当前 PWM 占空比。
例如:
u8 current_duty;
current_duty = drv_pwm_get_duty();
返回值范围:
0 ~ 100
这里返回的是驱动内部保存的 pwm_duty 值,即通过驱动 API 设置的逻辑占空比。
5.4 drv_pwm_start()
函数原型:
void drv_pwm_start(void);
启动 PCA PWM。
内部主要通过:
CR = 1;
启动 PCA 计数器。
例如:
drv_pwm_stop();
/* 其他操作 */
drv_pwm_start();
如果 PCA 已经处于运行状态,再次调用启动函数不会产生额外影响。
5.5 drv_pwm_stop()
函数原型:
void drv_pwm_stop(void);
停止 PCA PWM。
内部:
CR = 0;
停止 PCA 计数器。
停止 PWM 后,占空比设置不会丢失。
因此可以:
drv_pwm_stop();
drv_pwm_start();
重新恢复 PWM 输出。
六、PWM 初始化流程
PWM 驱动的初始化过程主要包括以下步骤:
1. 设置初始占空比为 0%
↓
2. 配置 P1.3 为推挽输出
↓
3. 设置 PCA 使用 P1 口
↓
4. 清除 PCA 控制寄存器
↓
5. 清零 PCA 计数器
↓
6. 设置 PCA 时钟为 FOSC/2
↓
7. 配置 PCA 模块 0 为 PWM 模式
↓
8. 设置 CCAP0H/L = 0xFF
↓
9. 启动 PCA
对应核心配置:
CCON = 0x00;
CL = 0x00;
CH = 0x00;
CMOD = 0x02;
CCAPM0 = 0x42;
CCAP0H = 0xFF;
CCAP0L = 0xFF;
CR = 1;
初始化完成之后,PWM 模块即可直接使用。
七、PWM 使用示例
一个完整的 PWM 使用示例:
#include "HRTOS_Control.h"
void main(void)
{
// 初始化 PWM
drv_pwm_init();
// 设置 50% 占空比
drv_pwm_set_duty(50);
// 运行一段时间
// ...
// 调整到 75%
drv_pwm_set_duty(75);
// 停止 PWM
drv_pwm_stop();
// 重新启动
drv_pwm_start();
// 设置 25%
drv_pwm_set_duty(25);
while(1)
{
// 主循环
}
}
可以看到,应用程序只需要调用几个简单的 API,即可完成 PWM 的初始化、参数调整、停止和重新启动。
这也是驱动库的一个重要作用:将底层硬件寄存器操作封装为更加直接的应用接口。
八、PWM 使用注意事项
使用 PWM 驱动时需要注意:
1. 芯片支持
当前 PWM 驱动依赖 STC 单片机的 PCA/PWM 硬件资源,例如:
STC12C5A60S2
因此并不是所有 51 单片机都能够直接使用该驱动。
2. PWM 输出引脚
当前默认输出:
P1.3
头文件中存在通过 AUXR1.6 切换 PCA/PWM 输出到 P4 口的相关定义,但当前驱动没有提供对应的公开引脚切换 API。
因此实际使用时应以当前驱动实现为准。
3. PWM 频率
PWM 使用:
FOSC/2
作为 PCA 时钟源。
实际 PWM 输出频率与单片机系统时钟频率以及 PCA PWM 工作方式有关,因此使用不同系统时钟时,需要根据实际时钟参数计算 PWM 频率。
4. 反转输出
当前 PWM 为反转输出逻辑:
寄存器值 0x00 → 100%
寄存器值 0xFF → 0%
但是用户 API 仍然使用:
drv_pwm_set_duty(0);
drv_pwm_set_duty(50);
drv_pwm_set_duty(100);
这种百分比方式进行控制。
5. PCA 资源占用
PWM 使用:
PCA 模块 0
因此如果应用程序中的其他功能也需要使用 PCA 模块,需要考虑硬件资源冲突。
九、Relay 继电器驱动
9.1 功能简介
除了 PWM 输出之外,HRTOS 4.0 05_Control 模块还提供继电器驱动。
继电器是 51 单片机控制系统中非常典型的执行设备,可以用于:
-
电机控制
-
灯光控制
-
风扇控制
-
电源控制
-
各类开关量设备控制
HRTOS 4.0 继电器驱动采用高电平触发设计。
主要功能包括:
-
继电器初始化
-
继电器开启
-
继电器关闭
-
继电器状态设置
-
继电器状态读取
十、Relay 文件组成
继电器驱动目录:
Relay/
├── relay_init.c
├── relay_on.c
├── relay_off.c
├── relay_set.c
└── relay_get.c
分别对应:
-
relay_init.c:继电器初始化 -
relay_on.c:继电器开启 -
relay_off.c:继电器关闭 -
relay_set.c:状态设置 -
relay_get.c:状态读取
PWM 和 Relay 均采用功能拆分的源文件组织方式。
十一、Relay 硬件接口
当前继电器驱动使用两个控制信号:
sbit RELAY_IN = P1^4;
sbit RELAY_EN = P0^0;
即:
RELAY_IN → P1.4
RELAY_EN → P0.0
其中:
-
RELAY_IN:继电器控制输入 -
RELAY_EN:继电器模块使能控制
当前设计采用高电平触发:
RELAY_IN = 1 → 继电器开启
RELAY_IN = 0 → 继电器关闭
需要注意,实际硬件连接应以当前驱动源码中的宏定义为准。
十二、Relay API
12.1 drv_relay_init()
函数原型:
void drv_relay_init(void);
用于初始化继电器。
初始化后:
继电器状态 = 关闭
RELAY_IN = 0
RELAY_EN = 1
示例:
#include "HRTOS_Control.h"
void main(void)
{
drv_relay_init();
// 继电器已初始化并关闭
}
12.2 drv_relay_on()
函数原型:
void drv_relay_on(void);
用于吸合继电器。
内部主要执行:
RELAY_EN = 1;
RELAY_IN = 1;
同时:
relay_state = 1;
示例:
drv_relay_on();
12.3 drv_relay_off()
函数原型:
void drv_relay_off(void);
用于释放继电器。
主要操作:
RELAY_IN = 0;
RELAY_EN = 1;
并将:
relay_state = 0;
示例:
drv_relay_off();
12.4 drv_relay_set()
函数原型:
void drv_relay_set(u8 state);
通过参数直接设置继电器状态。
state = 0 → 关闭
state = 1 → 开启
示例:
drv_relay_set(1);
drv_relay_set(0);
驱动内部根据状态调用对应的开启或关闭函数。
非 0 值按照开启处理。
12.5 drv_relay_get()
函数原型:
u8 drv_relay_get(void);
用于获取当前继电器的逻辑状态。
返回:
0 → 关闭
1 → 开启
例如:
u8 state;
state = drv_relay_get();
if(state == 1)
{
// 继电器处于开启状态
}
需要特别注意:
drv_relay_get() 返回的是驱动维护的 relay_state 逻辑状态,而不是直接读取继电器控制引脚的实际电平。
因此,如果应用程序绕过驱动直接操作 GPIO,状态变量可能不会同步变化。
十三、Relay 初始化与控制流程
继电器初始化流程:
drv_relay_init()
↓
relay_state = 0
↓
RELAY_IN = 0
↓
RELAY_EN = 1
↓
继电器关闭
开启:
drv_relay_on()
↓
RELAY_EN = 1
↓
RELAY_IN = 1
↓
relay_state = 1
↓
继电器吸合
关闭:
drv_relay_off()
↓
RELAY_IN = 0
↓
RELAY_EN = 1
↓
relay_state = 0
↓
继电器释放
十四、Relay 使用示例
完整示例:
#include "HRTOS_Control.h"
void main(void)
{
u8 state;
// 初始化继电器
drv_relay_init();
// 开启继电器
drv_relay_on();
// 获取当前状态
state = drv_relay_get();
// 关闭继电器
drv_relay_off();
// 使用状态设置接口
drv_relay_set(1);
drv_relay_set(0);
while(1)
{
// 主循环
}
}
通过统一的 drv_ API,可以避免应用程序直接操作具体 GPIO 寄存器。
十五、05_Control API 汇总
当前 05_Control 模块共提供 10 个公开 API。
| 模块 | API | 功能 |
|---|---|---|
| PWM | drv_pwm_init() | PWM 初始化 |
| PWM | drv_pwm_set_duty() | 设置占空比 |
| PWM | drv_pwm_get_duty() | 获取占空比 |
| PWM | drv_pwm_start() | 启动 PWM |
| PWM | drv_pwm_stop() | 停止 PWM |
| Relay | drv_relay_init() | 继电器初始化 |
| Relay | drv_relay_on() | 开启继电器 |
| Relay | drv_relay_off() | 关闭继电器 |
| Relay | drv_relay_set() | 设置继电器状态 |
| Relay | drv_relay_get() | 获取继电器状态 |
此外,模块还提供两个外部状态变量:
u8 pwm_duty;
u8 relay_state;
分别用于保存:
-
当前 PWM 占空比
-
当前继电器逻辑状态
十六、源码与接口一致性
针对 HRTOS 4.0 05_Control 模块,目前已经对头文件、驱动源文件和 API 进行了对应检查。
目前可以确认:
-
HRTOS_Control.h中声明的公开 API 均有对应实现 -
函数名称一致
-
参数类型一致
-
返回值类型一致
-
PWM 相关寄存器定义与实现一致
-
Relay 相关 GPIO 定义与实现一致
-
PWM 占空比转换方式与实现一致
-
PWM 反转输出逻辑与实现一致
-
继电器高电平触发逻辑与实现一致
-
示例代码中的主要 API 均为真实公开接口
文件覆盖情况:
PWM:
5 个源文件
5 个公开 API
Relay:
5 个源文件
5 个公开 API
整体上,当前模块已经形成比较完整的控制设备驱动结构。
十七、目前需要注意的几个问题
在驱动开发过程中,除了确认代码能够编译运行之外,硬件定义和文档描述的一致性同样重要。
当前 05_Control 模块还有几个需要进一步人工确认的地方。
1. Relay 引脚注释
头文件中的部分注释与实际宏定义存在方向上的差异。
当前源码定义为:
RELAY_IN = P1^4;
RELAY_EN = P0^0;
因此实际硬件连接应以源码定义为准,并建议后续统一头文件注释。
2. PWM 频率
目前只明确配置:
PCA 时钟 = FOSC/2
实际 PWM 频率还与系统时钟及 PWM 工作方式有关,因此后续可以进一步补充具体频率计算说明。
3. PWM 引脚切换
头文件中存在 AUXR1.6 相关的 P4 PWM 引脚切换说明,但目前没有提供对应的公开 API。
当前驱动主要使用默认的:
P1.3
4. u8 类型定义
部分接口使用:
u8
如果用户工程没有提供对应类型定义,需要确认 u8 的实际定义来源。
5. RELAY_EN 的具体作用
当前代码中 RELAY_EN 初始化后保持:
1
因此其具体硬件意义还需要结合实际继电器模块电路进行确认。
6. Relay 状态读取
drv_relay_get() 返回的是:
relay_state
而不是实际 GPIO 电平。
因此它代表的是驱动逻辑状态,而不是对继电器机械触点或实际硬件状态的反馈检测。
十八、从 GPIO 操作到控制设备驱动
对于 51 单片机开发而言,PWM 和继电器本身并不复杂。
真正值得关注的是:应用程序是否需要直接面对底层硬件细节。
例如传统写法可能需要直接操作:
CCON
CMOD
CCAPM0
CCAP0H
CCAP0L
而使用 HRTOS 4.0 Driver Library 后,上层应用可以直接使用:
drv_pwm_init();
drv_pwm_set_duty(50);
drv_pwm_stop();
drv_pwm_start();
继电器同样可以从:
P1^4 = 1;
这样的底层 GPIO 操作,进一步封装成:
drv_relay_on();
这就是驱动库存在的意义之一:
让应用程序关注“控制什么”,而不是反复处理“底层硬件寄存器怎么控制”。
对于一个面向 51 单片机的实时操作系统而言,这种驱动接口也是操作系统与具体硬件之间的重要连接层。
十九、HRTOS 4.0 与 51 单片机驱动开发
HRTOS 4.0 的 Driver Library 正在逐步覆盖 51 单片机开发中常见的硬件设备。
05_Control 主要解决的是控制类硬件资源:
HRTOS 4.0
│
Driver Library
│
05_Control
/ \
/ \
PWM Relay
│ │
PCA GPIO
│ │
51单片机控制系统
其中 PWM 更偏向于连续控制,例如调节输出比例;继电器则更偏向于开关控制。
二者结合后,可以覆盖不少典型的 51 单片机控制应用。
例如:
传感器
↓
HRTOS任务
↓
控制逻辑
↓
05_Control
├── PWM
└── Relay
↓
执行设备
这样,传感器、任务调度、控制算法和硬件执行设备就能够形成一个完整的嵌入式控制链路。
二十、HRTOS 官方网站
HRTOS 是一个面向 51 单片机 / 8051 的实时操作系统项目,项目持续完善操作系统内核、API、驱动库、实验例程以及相关技术文档。
如果希望进一步了解 HRTOS 4.0、Driver Library、API 文档以及 51 单片机实时操作系统相关内容,可以访问:
HRTOS 官方网站:
网站提供 HRTOS 项目介绍、技术文档、开发资料及相关资源。
二十一、总结
HRTOS 4.0 Driver Library 05_Control 模块目前提供了 PWM 和 Relay 两类控制设备驱动。
其中:
PWM:
-
基于 PCA 模块
-
支持 0~100% 占空比设置
-
支持占空比读取
-
支持启动与停止
-
默认使用 P1.3
-
采用 FOSC/2 作为 PCA 时钟源
Relay:
-
支持继电器初始化
-
支持开启与关闭
-
支持状态设置
-
支持状态读取
-
当前采用高电平触发
-
使用 P1.4 与 P0.0 控制信号
整个模块共提供 10 个公开 API,并按照 PWM 与 Relay 两个子模块进行组织。
对于 51 单片机和 8051 开发者来说,控制设备驱动是连接软件逻辑与实际硬件的重要一层。HRTOS 4.0 通过 Driver Library 对常用硬件进行统一封装,可以让上层应用更加直接地使用硬件控制能力,同时也进一步完善 HRTOS 在 51 单片机实时操作系统、嵌入式驱动开发和实际应用开发 方面的软件生态。
HRTOS —— 面向 8051/51 单片机的实时操作系统。
关键词
HRTOS 4.0、HRTOS、51单片机、8051、51单片机操作系统、实时操作系统、嵌入式操作系统、驱动开发、单片机驱动、PWM驱动、PCA、STC12C5A60S2、继电器驱动、控制设备驱动、嵌入式开发
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐
所有评论(0)