模块来源
规格参数
工作电压:3.3V-5V
工作电流:< 20mA
输出格式:模拟信号输出
控制接口:ADC
管脚数量:3 Pin(2.54mm间距排针)
以上信息见厂家资料文件
移植过程
我们的目标是将例程移植至开发板上【能够判断当前环境状况的功能】。首先要获取资料,查看数据手册应如何实现读取数据,再移植至我们的工程。
查看资料
灰度传感器包括一个白色高亮发光二极管和一个光敏电阻,由于发光二极管照射到灰度不同的纸张上返回的光是不同的,光敏电阻接收到返回的光,根据光的强度不同,光敏电阻的阻值也不同,从而实现灰度值的测试。
引脚选择
这里选择的引脚见引脚接线表
☠ 特别注意
我们的芯片是 D133EBS
它的ADC参考电压是2.5V
, 最高只能读到2.5V(也就是输入3.3V它显示出来的也是2.5V) ,所以我们需要在外面给它进行分压,将模块输出的最高3.3V电压分压成最高1.65V,然后在程序中将ADC读到的数据乘2
得到真实的数据。
进行分压会损失一定的精度,但这是必要的!
分压计算公式:
原理图结构:
根据计算公式,我们可以算出来分压之后的电压为模块AO引脚输出的一半!!
代码移植
下载为大家准备的驱动代码文件夹,复制到自己工程中\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/grayscale-sensor/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 grayscale sensor
后按 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_grayscale.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_grayscale.h"
// adc设备名称
#define ADC_DEVICE_NAME "gpai"
// adc通道
#define ADC_CHANNEL 6
// 电压基准
#define VREF_ADC_HSPI 2.5
static struct rt_adc_device *adc_dev = NULL;
/**********************************************************
* 函 数 名 称:Grayscale_Init
* 函 数 功 能:初始化ADC
* 传 入 参 数:无
* 函 数 返 回:RT_EOK成功 -RT_ERROR失败
* 作 者:LCKFB
* 备 注:LP
**********************************************************/
int Grayscale_Init(void)
{
// 获取设备句柄
adc_dev = (struct rt_adc_device *)rt_device_find(ADC_DEVICE_NAME);
if (adc_dev == RT_NULL)
{
LOG_E("Failed to open %s device", ADC_DEVICE_NAME);
return -RT_ERROR;
}
// 使能adc通道
int ret = rt_adc_enable(adc_dev, ADC_CHANNEL);
if(ret != RT_EOK)
{
LOG_E("Failed to [rt_adc_enable] !!!");
return -RT_ERROR;
}
aicos_mdelay(200);
return RT_EOK;
}
/**********************************************************
* 函 数 名 称:Grayscale_DeInit
* 函 数 功 能:清除ADC初始化
* 传 入 参 数:无
* 函 数 返 回:RT_EOK成功 -RT_ERROR失败
* 作 者:LCKFB
* 备 注:LP
**********************************************************/
int Grayscale_DeInit(void)
{
int ret = rt_adc_disable(adc_dev, ADC_CHANNEL);
if(ret != RT_EOK)
{
LOG_E("[%d]:Failed to [rt_adc_disable] !!!", __LINE__);
return -RT_ERROR;
}
return RT_EOK;
}
/**********************************************************
* 函 数 名 称:Grayscale_Get_Value
* 函 数 功 能:获得某个通道的值
* 传 入 参 数:电压存储地址
* 函 数 返 回:RT_EOK成功 -RT_ERROR失败
* 作 者:LCKFB
* 备 注:ADC每个时间
**********************************************************/
int Grayscale_Get_Value(float *Voltage)
{
int value = 0; // 累计读取的数据
int count = 5; // 采集次数
int valid_count = 0; // 有效读取次数
int return_Value = 0; // 分压之后还原的数据
while(count--)
{
uint32_t temp = rt_adc_read(adc_dev, ADC_CHANNEL);
if(temp < 4096) // 确保不会把校验数据计算进来
{
// rt_kprintf("[%d]adc temp = [%d]\n",valid_count+1,temp);
value += temp;
valid_count++;
}
aicos_mdelay(5); // 延时5ms
}
// 如果没有有效的读取
if(!valid_count)
{
return -RT_ERROR; // 返回一个错误代码
}
return_Value = value / valid_count; // 计算平均值
/* 因为电压分压为了二分之一所以需要还原 */
*Voltage = (( VREF_ADC_HSPI / 4095.0 ) * return_Value) * 2; // 换算成电压
return RT_EOK;
}
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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
bsp_grayscale.h
/*
* 立创开发板软硬件资料与相关扩展板软硬件资料官网全部开源
* 开发板官网:www.lckfb.com
* 文档网站:wiki.lckfb.com
* 技术支持常驻论坛,任何技术问题欢迎随时交流学习
* 嘉立创社区问答:https://www.jlc-bbs.com/lckfb
* 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
* 不靠卖板赚钱,以培养中国工程师为己任
*/
#ifndef __BSP_GRAYSCALE_H__
#define __BSP_GRAYSCALE_H__
#include "stdio.h"
int Grayscale_Init(void);
int Grayscale_DeInit(void);
int Grayscale_Get_Value(float *Voltage);
#endif
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Kconfig
这个是一个menuconfig中的选项,如果在菜单中选中该选项,就会在rtconfig.h
中定义一个语句,用来if判断条件编译之类的。
config LCKFB_GRAYSCALE_SENSOR
bool "USing grayscale sensor"
select AIC_USING_GPAI
select AIC_USING_GPAI6
default n
help
More information is available at: https://wiki.lckfb.com/
2
3
4
5
6
7
8
SConscript
自动化构建文件,如果定义了 LCKFB_GRAYSCALE_SENSOR
和 USING_LCKFB_TRANSPLANT_CODE
就自动编译当前目录下的文件!!
Import('RTT_ROOT')
Import('rtconfig')
import rtconfig
from building import *
cwd = GetCurrentDir()
CPPPATH = [cwd]
src = []
if GetDepend('LCKFB_GRAYSCALE_SENSOR') and GetDepend('USING_LCKFB_TRANSPLANT_CODE'):
src = Glob(os.path.join(cwd, '*.c'))
group = DefineGroup('lckfb-grayscale-sensor', src, depend = [''], CPPPATH = CPPPATH)
Return('group')
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
test_grayscale_sensor.c
这个文件定义了一个用于处理灰度传感器的线程,初始化了灰度传感器,并设置了线程的优先级、栈大小和时间片。 线程的主要任务是周期性地读取灰度传感器的模拟输出值,并将其转换为电压值。读取到的数据会被打印到控制台。通过命令行接口,用户可以启动和退出这个线程来测试灰度传感器的功能。
线程入口函数逻辑
- 定义一个循环次数变量
while_count
,用于控制读取次数。 - 在一个无限循环中,执行以下任务:
- 调用
Grayscale_Get_Value
函数读取传感器的模拟输出值,并将其转换为电压值。 - 判断读取操作是否成功,如果失败则打印错误信息。
- 如果读取成功,将电压值乘以100以保留两位小数,并打印电压值。
- 每次循环结束时,线程会休眠1000毫秒。
- 当循环次数达到100次时,提示用户可以通过输入命令来退出传感器测试,并重置循环次数。
- 在两次读取之间,线程会额外休眠2000毫秒。
- 调用
灰度传感器启动函数逻辑
- 调用
Grayscale_Init
函数初始化灰度传感器。 - 如果初始化成功,创建名为"grayscale_thread"的线程,入口函数为
grayscale_thread_entry
,无参数,设置栈大小、优先级和时间片。 - 如果线程创建成功,启动线程。
提示
MSH_CMD_EXPORT
宏将test_grayscale_sensor
和test_exit_grayscale_sensor
函数导出为RT-Thread命令行接口的命令,这样用户可以在RT-Thread的命令行中直接运行以下命令来控制灰度传感器的行为:
grayscale sensor test
启动灰度传感器测试。exit grayscale sensor test
停止灰度传感器线程,并进行去初始化。
退出函数逻辑
- 调用
rt_thread_delete
函数尝试删除grayscale_thread
线程。 - 如果删除成功,调用
Grayscale_DeInit
函数去初始化灰度传感器。 - 如果去初始化成功,打印退出成功的提示信息。
- 如果任何步骤失败,打印相应的错误信息。
#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_grayscale.h"
#define THREAD_PRIORITY 25 // 线程优先级
#define THREAD_STACK_SIZE 1024 // 线程大小
#define THREAD_TIMESLICE 25 // 时间片
static rt_thread_t grayscale_thread = RT_NULL; // 线程控制块
// 线程入口函数
static void grayscale_thread_entry(void *param)
{
int while_count = 1;
while(while_count++)
{
/* 电压数值缓存区 */
float Voltage = 0;
/* 判断是否读取成功 */
if(RT_EOK != Grayscale_Get_Value(&Voltage))
{
LOG_E("Failed to Grayscale_Get_Value !!!");
}
else
{
/* 将数字扩大100倍 */
uint32_t temp_voltage = Voltage * 100;
/* 打印数据,分别处理小数点前的数据和后面的数据! */
rt_kprintf("\nRead Voltage_Value = %d.%02dV\n", temp_voltage/100, temp_voltage%100); // 电压
}
/* 循环提示 */
if(while_count >= 100)
{
while_count = 1;
rt_kprintf("\nType [test_exit_grayscale_sensor] command to exit \n");
rt_kprintf("Note: Pressing [TAB] as you type will autocomplete the command\n");
rt_thread_mdelay(2000);
}
rt_thread_mdelay(1000);
}
}
static void test_grayscale_sensor(int argc, char **argv)
{
int ret = Grayscale_Init();
if(ret != RT_EOK)
{
LOG_E("Failed to [Grayscale_Init] !!!");
return;
}
/* 创建线程,名称是 grayscale_thread,入口是 grayscale_thread_entry */
grayscale_thread = rt_thread_create("grayscale_thread",
grayscale_thread_entry, RT_NULL,
THREAD_STACK_SIZE,
THREAD_PRIORITY, THREAD_TIMESLICE);
/* 如果获得线程控制块,启动这个线程 */
if (grayscale_thread != RT_NULL)
rt_thread_startup(grayscale_thread);
}
// 导出函数为命令
MSH_CMD_EXPORT(test_grayscale_sensor, grayscale sensor test);
/* 退出函数 */
void test_exit_grayscale_sensor(void)
{
int ret = rt_thread_delete(grayscale_thread);
if(ret != RT_EOK)
{
LOG_E("failed to test_exit_grayscale_sensor !!");
return;
}
ret = Grayscale_DeInit();
if(ret != RT_EOK)
{
LOG_E("Failed to [Grayscale_DeInit] !!!");
return;
}
else
{
rt_kprintf("\nGrayscale_DeInit successful!!!\n");
}
rt_kprintf("\n========grayscale sensor exit successful !!========\n");
}
// 导出函数为命令
MSH_CMD_EXPORT(test_exit_grayscale_sensor, exit grayscale sensor 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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
移植验证
我们使用串口调试,将 USB转TTL模块 连接到衡山派开发板上面!!
具体的教程查看:串口调试(点击跳转🚀)
串口波特率默认为
115200
我们在输入下面的命令运行该模块的线程:
输入的时候按下
TAB键
会进行命令补全!!
test_grayscale_sensor
模块上电效果: