继电器是控制电路的电子元器件,通过感应输入电流的变化控制电路的通断,通常用于自动化控制电路中,在电路中起着自动调节、隔离、安全保护和转换等作用。直流继电器通常有5个引脚,其中有两个引脚是线圈控制引脚,其他3个引脚分别是是常开端、常闭端和公共端。在没有上电时,线圈没有通电,常闭端和公共端相连,常开端和公共端断开;上电后,线圈通电,常开端和公共端相连,常闭端和公共端断开。所以继电器就相当于是一个开关,可以使用低压控制高压。
模块来源
规格参数
工作电压:5V
可控制的交流电压范围:可达250V,10A
可控制的交流电压范围:可达30V,10A
控制方式:GPIO
管脚数量:4 Pin(2.54mm间距排针)
说明:采用光耦隔离保护MCU引脚;采用三极管驱动;
以上信息见厂家资料文件
移植过程
我们的目标是将例程移植至开发板上【能够实现控制继电器的吸合与释放的功能】。首先要获取资料,查看数据手册应如何实现读取数据,再移植至我们的工程。
查看资料
如果继电器在低压电源导通的状态下,电磁铁有了磁力,吸合衔铁,触点闭合,高压电源形成回路处于导通状态;如果继电器在低压电源断开的状态下,电磁铁没有磁力,因为弹簧的缘故,弹簧将触点断开,高压电源没有形成回路处于断开状态;
知道了控制原理,再来看原理图。K1为继电器,其中的4脚和5脚是继电器的低压电源控制引脚,当IN1输出低电平,U1光耦隔离器的1脚2脚导通使得4脚和3脚导通,VCC通过4脚到3脚经过R2给三极管的基极得电,因为三极管的基极得电,使得三极管导通,VCC经过继电器的4脚到5脚到三极管到地。因此继电器的线圈得电,继电器的1脚触点由2脚吸合到3脚,达到了我们控制开关的目的。其中原理图中的P1端子的1脚是常闭触点,2脚是公共触点,3脚是常开触点。对应的接线图见下方右图。
引脚选择
这里选择的引脚见引脚接线表
代码移植
下载为大家准备的驱动代码文件夹,复制到自己工程中\luban-lite\application\rt-thread\helloworld\user-bsp
文件夹下
提示
如果未找到 user-bsp
这个文件夹,说明你未进行模块移植的前置操作。请转移到手册使用必要操作(点击跳转)中进行必要的配置操作!!!
接下来打开自己的工程,开始修改Kconfig文件。
1、在 VSCode 中打开 application\rt-thread\helloworld\Kconfig 文件
2、在该文件的 #endif
前面添加该模块的 Kconfig路径语句
# 继电器模块
source "application/rt-thread/helloworld/user-bsp/relay-module/Kconfig"
2
menuconfig操作
1、我们 双击 luban-lite
文件夹下的 win_env.bat
脚本打开env工具:
2、输入以下命令列出所有可用的默认配置:
scons --list-def
3、选择 d13x_JLC_rt-thread_helloworld
这个配置!这个是我们衡山派开发板的默认配置!输入以下命令即可:
scons --apply-def=7
或者
scons --apply-def=d13x_JLC_rt-thread_helloworld_defconfig
这两个命令作用是一样的,一个是 文件名 ,一个是 编号 !!!
4、输入以下命令进入menuconfig菜单
scons --menuconfig
进入以下界面:
5、选中 Porting code using the LCKFB module
按
Y
选中按
N
取消选中方向键
左右
调整 最下面菜单的选项方向键
上下
调整 列表的选项
回车
执行最下面菜单的选项
6、回车进入 Porting code using the LCKFB module
菜单
7、按方向键 上下
选中 Using Relay module
后按 Y
键,看到前面括号中出现一个 *
号,就可以下一步了。
8、按方向键 左右
选中 <Save>
然后一路回车
,然后 退出
即可
编译
我们 保存并退出menuconfig菜单 之后,输入以下命令进行编译:
scons
或
scons -j16
-j 用来选择参与编译的核心数: 我这里是选择16
大家可以根据自己的电脑来选择
核心越多编译越快
如果写的数量高于电脑本身,那么就自动按照最高可用的来运行!
镜像烧录
编译完成之后会在 \luban-lite\output\d13x_JLC_rt-thread_helloworld\images
文件夹下生成一个 d13x_JLC_v1.0.0.img
镜像文件!
然后我们烧录镜像,具体的教程请查看:镜像烧录(点击跳转🚀)
到这里完成了,请移步到 最后一节 进行移植验证。
工程代码解析
bsp_relay.c
/*
* 立创开发板软硬件资料与相关扩展板软硬件资料官网全部开源
* 开发板官网:www.lckfb.com
* 文档网站:wiki.lckfb.com
* 技术支持常驻论坛,任何技术问题欢迎随时交流学习
* 嘉立创社区问答:https://www.jlc-bbs.com/lckfb
* 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
* 不靠卖板赚钱,以培养中国工程师为己任
*/
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <sys/time.h>
#include <rtthread.h>
#include "hal_adcim.h"
#include "rtdevice.h"
#include "aic_core.h"
#include "aic_log.h"
#include "hal_gpai.h"
#include <stdio.h>
#include "aic_hal_gpio.h"
#include "bsp_relay.h"
// 引脚号获取
#define RELAY_CONTROL_PIN rt_pin_get("PE.14")
// 引脚状态设定
#define RELAY_SET_PIN_LEVEL(x) rt_pin_write(RELAY_CONTROL_PIN, x ? PIN_HIGH : PIN_LOW)
/**********************************************************
* 函 数 名 称:RELAY_Init
* 函 数 功 能:初始化继电器模块
* 传 入 参 数:无
* 函 数 返 回:RT_EOK成功 -RT_ERROR失败
* 作 者:LCKFB
* 备 注:
**********************************************************/
int RELAY_Init(void)
{
// 设定DO引脚的模式
rt_pin_mode(RELAY_CONTROL_PIN, PIN_MODE_OUTPUT);
return RT_EOK;
}
/******************************************************************
* 函 数 名 称:RELAY_Set_State
* 函 数 说 明:设置继电器模块的状态
* 函 数 形 参:state要设置的目标状态
* 函 数 返 回:RT_EOK成功 -RT_ERROR失败
* 作 者:LCKFB
* 备 注:无
******************************************************************/
int RELAY_Set_State(uint8_t state)
{
switch (state)
{
case 1:
RELAY_SET_PIN_LEVEL(1); // 断开
return RT_EOK;
case 0:
RELAY_SET_PIN_LEVEL(0); // 吸合
return RT_EOK;
default:
break;
}
return -RT_ERROR;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
bsp_relay.h
/*
* 立创开发板软硬件资料与相关扩展板软硬件资料官网全部开源
* 开发板官网:www.lckfb.com
* 文档网站:wiki.lckfb.com
* 技术支持常驻论坛,任何技术问题欢迎随时交流学习
* 嘉立创社区问答:https://www.jlc-bbs.com/lckfb
* 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
* 不靠卖板赚钱,以培养中国工程师为己任
*/
#ifndef __BSP_RELAY_H__
#define __BSP_RELAY_H__
#include "stdio.h"
int RELAY_Init(void);
int RELAY_Set_State(uint8_t state);
#endif
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Kconfig
这个是一个menuconfig中的选项,如果在菜单中选中该选项,就会在rtconfig.h
中定义一个语句,用来if判断条件编译之类的。
config LCKFB_RELAY_MODULE
bool "Using Relay module"
default n
help
More information is available at: https://wiki.lckfb.com/
2
3
4
5
6
SConscript
自动化构建文件,如果定义了 LCKFB_RELAY_MODULE
和 USING_LCKFB_TRANSPLANT_CODE
就自动编译当前目录下的文件!!
Import('RTT_ROOT')
Import('rtconfig')
import rtconfig
from building import *
cwd = GetCurrentDir()
CPPPATH = [cwd]
src = []
if GetDepend('LCKFB_RELAY_MODULE') and GetDepend('USING_LCKFB_TRANSPLANT_CODE'):
src = Glob(os.path.join(cwd, '*.c'))
group = DefineGroup('lckfb-relay-module', src, depend = [''], CPPPATH = CPPPATH)
Return('group')
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
test_relay_module.c
这个文件定义了一个处理继电器模块的线程,初始化了继电器模块的板级支持包(BSP),并设置了线程的优先级、栈大小和时间片。
线程的主要任务是循环控制继电器的吸合和断开状态,并在每次状态改变后延时1秒。当循环次数达到100次时,会提示用户可以通过输入命令来退出继电器控制循环。
以下是代码中的关键点:
THREAD_PRIORITY
、THREAD_STACK_SIZE
和THREAD_TIMESLICE
分别定义了线程的优先级、栈大小和时间片。relay_thread
是线程控制块的指针,初始为RT_NULL
。relay_thread_entry
是线程的入口函数,它执行继电器状态的控制循环。RELAY_Set_State
函数用于设置继电器的状态(吸合或断开)。aicos_mdelay
函数用于实现毫秒级的延时。LOG_E
宏用于打印错误信息。test_relay_module
函数用于初始化继电器模块并创建线程。MSH_CMD_EXPORT
宏用于将函数导出为命令行接口,使得用户可以在命令行中直接调用这些函数。
在 relay_thread_entry
函数中,有一个无限循环,循环体内会交替设置继电器的吸合和断开状态,并在每次状态改变后延时1秒。当循环次数达到100次时,会打印提示信息,告知用户如何退出继电器控制循环。
test_exit_relay_module
函数用于退出继电器控制循环,它通过调用 rt_thread_delete
函数来删除线程。如果删除成功,会打印退出成功的消息;如果删除失败,会打印错误信息。
用户可以通过在命令行中输入 test_relay_module
来启动继电器模块的线程,输入 test_exit_relay_module
来退出继电器控制循环。
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <getopt.h>
#include <sys/time.h>
#include <rtthread.h>
#include "rtdevice.h"
#include "aic_core.h"
#include "aic_hal_gpio.h"
#include "bsp_relay.h"
#define THREAD_PRIORITY 25 // 线程优先级
#define THREAD_STACK_SIZE 1024 // 线程大小
#define THREAD_TIMESLICE 25 // 时间片
static rt_thread_t relay_thread = RT_NULL; // 线程控制块
// 线程入口函数
static void relay_thread_entry(void *param)
{
int while_count = 1;
while(while_count++)
{
if(RT_EOK != RELAY_Set_State(0)) //控制继电器吸合
{
LOG_E("The suction state is wrong !!");
}
rt_thread_mdelay(1000);
if(RT_EOK != RELAY_Set_State(1)) //控制继电器断开
{
LOG_E("Disconnected status error !!");
}
rt_thread_mdelay(1000);
/* 循环提示 */
if(while_count >= 100)
{
while_count = 1;
rt_kprintf("\nType [test_exit_relay_module] command to exit \n");
rt_kprintf("Note: Pressing [TAB] as you type will autocomplete the command\n");
rt_thread_mdelay(2000);
}
}
}
static void test_relay_module(int argc, char **argv)
{
int ret = RELAY_Init();
if(ret != RT_EOK)
{
LOG_E("Failed to [RELAY_Init] !!!");
return;
}
/* 创建线程,名称是 relay_thread,入口是 relay_thread_entry */
relay_thread = rt_thread_create("relay_thread",
relay_thread_entry, RT_NULL,
THREAD_STACK_SIZE,
THREAD_PRIORITY, THREAD_TIMESLICE);
/* 如果获得线程控制块,启动这个线程 */
if (relay_thread != RT_NULL)
rt_thread_startup(relay_thread);
}
// 导出函数为命令
MSH_CMD_EXPORT(test_relay_module, relay module test);
/* 退出函数 */
void test_exit_relay_module(void)
{
int ret = rt_thread_delete(relay_thread);
if(ret != RT_EOK)
{
LOG_E("failed to test_exit_relay_module !!");
return;
}
rt_kprintf("\n========relay module exit successful !!========\n");
}
// 导出函数为命令
MSH_CMD_EXPORT(test_exit_relay_module, exit relay module test);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
移植验证
我们使用串口调试,将 USB转TTL模块 连接到衡山派开发板上面!!
具体的教程查看:串口调试(点击跳转🚀)
串口波特率默认为
115200
我们在输入下面的命令运行该模块的线程:
输入的时候按下
TAB键
会进行命令补全!!
test_relay_module