数码管设备
前面系统移植时候,已经将数码管的小数点位作为系统指示灯,所以在这的数码管设备就屏蔽掉小数点位,保持独立。
数码管IO配置
先看硬件原理图
数码管是共阳数码管,另一脚接到PC0~PC7,PC7已经用来做系统指示灯,把对应引脚电平拉低,对应数码管段就点亮。GPIO在RT-thread中已经默认注册,只需在驱动中初始化IO口模式即可。
数码管设备配置
数码管属于板上设备,接下来要干三件事,创建驱动文件、添加Kconfig配置项、修改SConscript文件依赖。
在对应bsp的“\board\ports”目录下(没有“ports”文件夹就自行创建)创建“drv_digitron.c”和“drv_digitron.h”文件,作为驱动文件,驱动内容后面写。
打开对应bsp的“\board”目录下的“Kconfig”文件,在以下的菜单目录下
menu “Onboard Peripheral Drivers”
添加以下字段
config BSP_USING_DIGITRON
bool "Enable DIGITRON"
select BSP_USING_GPIO
default n
打开对应bsp的“\board”目录下的“SConscript”文件,在这个字眼后面
src = Split('''
board.c
CubeMX_Config/Src/stm32f1xx_hal_msp.c
''')
添加文件依赖
if GetDepend(['BSP_USING_DIGITRON']):
src += Glob('ports/drv_digitron.c')
如果没有包含“ports”头文件路径,则需要在“path”定义的字眼后面添加头文件路径
path += [cwd + '/ports']
这三件事做完后,就打开图形化配置工具
menuconfig
进入到以下目录
Hardware Drivers Config
—> Onboard Peripheral Drivers
选中刚才新增“Enable DIGITRON”项,保存配置,退出,重新生成工程。
scons --target=mdk5
打开工程,发现工程中添加了刚才新创建的“drv_digitron.c”和“drv_digitron.h”文件,编译,没有报错,接下来就是完成驱动的编写。
数码管驱动编写
驱动头文件中,首先就包含以下三个驱动必备的头文件
#include <rtthread.h>
#include "rtdevice.h"
#include <drv_common.h>
然后就是定义数码管设备结构体,因为数码管设备简单,直接继承设备通用类即可
struct drv_digitron_device
{
struct rt_device parent;
};
源文件首先添加以下东西
#include <rtthread.h>
#include "drv_gpio.h" // 是从gpio驱动衍生出来的数码管驱动
#include "drv_digitron.h"
#define DBG_TAG "drv.digitron"
#include <drv_log.h>
然后定义一个单例静态设备实体
static struct drv_digitron_device _digitron;
接下来就根据通用设备的函数操作集来完成相应的函数
/**
* operations set for device object
*/
struct rt_device_ops
{
/* common device interface */
rt_err_t (*init) (rt_device_t dev);
rt_err_t (*open) (rt_device_t dev, rt_uint16_t oflag);
rt_err_t (*close) (rt_device_t dev);
rt_size_t (*read) (rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size);
rt_size_t (*write) (rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size);
rt_err_t (*control)(rt_device_t dev, int cmd, void *args);
};
在数码管设备里面,目前需要用到的函数,就只有初始化和写,控制函数的话也可以根据情况添加。
首先是初始化函数,初始化函数里面需要完成的一般是两部分内容,一个是硬件的初始化,一个是软件的初始化(这个软件的初始化可以适当的在有打开函数里面完成)。参考如下
void digitron_pin_init(void)
{
rt_pin_mode(GET_PIN(C, 0), PIN_MODE_OUTPUT);
rt_pin_mode(GET_PIN(C, 1), PIN_MODE_OUTPUT);
rt_pin_mode(GET_PIN(C, 2), PIN_MODE_OUTPUT);
rt_pin_mode(GET_PIN(C, 3), PIN_MODE_OUTPUT);
rt_pin_mode(GET_PIN(C, 4), PIN_MODE_OUTPUT);
rt_pin_mode(GET_PIN(C, 5), PIN_MODE_OUTPUT);
rt_pin_mode(GET_PIN(C, 6), PIN_MODE_OUTPUT);
digitron_show(0);
}
把这个初始化函数放在标准接口里面调用即可。其中显示函数如下
// 0~F
uint8_t digitron_ascii_map[16] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F, 0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71};
void digitron_show(uint8_t data)
{
uint8_t i = 0;
if ((0 <= data && data < sizeof(digitron_ascii_map) / sizeof(digitron_ascii_map[0])) ||
data == 0xFF)
{
for (i = 0; i < 7; i++) // 小数点做系统灯,不用处理
{
rt_pin_write(GET_PIN(C, i), ((digitron_ascii_map[data] >> i) & 1) == 1 ? PIN_LOW : PIN_HIGH);
}
}
}
然后写函数,参考如下
static rt_size_t drv_digitron_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
{
RT_ASSERT(dev);
RT_ASSERT(size <= sizeof(uint8_t));
uint8_t data = (uint8_t)buffer;
digitron_show(data);
return sizeof(data);
}
就是“buffer”传进什么数字就显示什么数字。
控制函数,参考如下
static rt_err_t drv_digitron_control(rt_device_t dev, int cmd, void *args)
{
struct drv_digitron_device *digitron = (struct drv_digitron_device *)dev;
switch (cmd)
{
case DIGITRON_CTRL_SET_SHOW:
{
uint8_t data = (uint8_t)args;
uint8_t i = 0;
for (i = 0; i < 7; i++) // 小数点做系统灯,不用处理
{
rt_pin_write(GET_PIN(C, i), ((data >> i) & 1) == 1 ? PIN_LOW : PIN_HIGH);
}
}
break;
}
return RT_EOK;
}
控制函数,“DIGITRON_CTRL_SET_SHOW”命令可以控制数码管显示特定内容。
最后就是将设备注册到系统。
#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops digitron_ops = {
drv_digitron_init,
RT_NULL,
RT_NULL,
RT_NULL,
drv_digitron_write,
drv_digitron_control
};
#endif
int drv_digitron_hw_init(void)
{
rt_err_t result = RT_EOK;
struct rt_device *device = &_digitron.parent;
/* memset _digitron to zero */
rt_memset(&_digitron, 0x00, sizeof(_digitron));
device->type = RT_Device_Class_Miscellaneous;
#ifdef RT_USING_DEVICE_OPS
device->ops = &digitron_ops;
#else
device->init = drv_digitron_init;
device->write = drv_digitron_write;
device->control = drv_digitron_control;
#endif
device->user_data = RT_NULL;
/* register digitron device */
result = rt_device_register(device, "digitron", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE);
if (result != RT_EOK)
{
LOG_E("digitron register err code: %d", result);
return result;
}
LOG_I("digitron register success");
return result;
}
INIT_DEVICE_EXPORT(drv_digitron_hw_init);
文件链接
结尾
rtthread学习中,打开主页查看更多笔记