【BES2500x系列 -- RTX5操作系统】Battery模块 -- 细说 ADC 采集的一次流程 --(十六)

请添加图片描述

  • 💌 所属专栏:【BES2500x系列】

  • 😀 作  者:我是夜阑的狗🐶

  • 🚀 个人简介:一个正在努力学技术的CV工程师,专注基础和实战分享 ,欢迎咨询!

  • 💖 欢迎大家:这里是CSDN,我总结知识的地方,喜欢的话请三连,有问题请私信 😘 😘 😘

您的点赞、关注、收藏、评论,是对我最大的激励和支持!!!🤩 🤩 🤩

请添加图片描述


前言

  大家好,又见面了,我是夜阑的狗🐶,本文是专栏【BES2500x系列】专栏的第16篇文章;
  今天开始学习BES2500x系列的一天💖💖💖,开启新的征程,记录最美好的时刻🎉,每天进步一点点。
  专栏地址:【BES2500x系列】, 此专栏是我是夜阑的狗对BES2500x系列开发过程的总结,希望能够加深自己的印象,以及帮助到其他的小伙伴😉😉。
  如果文章有什么需要改进的地方还请大佬不吝赐教👏👏。


1 电池电量检测定时器

  前面已经讲解了 Battery 模块在系统初始化的过程中,创建两个定时器,分别是电池电量定时器和出入盒检测定时器。接下来就让我们来看一下这些定时器里都在执行什么逻辑吧,这里引用黑神话的一个梗,我若不了解该定时器,众生怎知我,尘缘已断,金海尽干(注:此处只是为了玩梗,勿要较真)。话不多说,让我们原文再续,书接上回。

在这里插入图片描述

1.1 app_battery_timer_handler()

  从上一篇文章的 osTimerDef (APP_BATTERY, app_battery_timer_handler); 中看到 app_battery_timer_handlerAPP_BATTERY 定时器钩子函数,来看一下该函数触发时都会执行什么吧。

  • 代码
/**
 * @brief 电池定时器处理函数
 * 
 * 该函数负责打开GPADC(通用用途模数转换器),用于电池电量监测。它配置GPADC为一次性转换模式,并指定中断处理函数。
 * 这个定时器处理函数可能由一个定时器事件触发,用以定期检查电池电压。
 * 
 * @param param 传入的参数指针。当前实现中未使用。
 */
static void app_battery_timer_handler(void const *param)
{
    // 打开GPADC,配置为一次性转换模式,并绑定电池电压监测的中断处理函数
    // 这里使用HAL_GPADC_ATP_ONESHOT模式,意味着GPADC将在完成一次转换后自动停止
    // app_battery_irqhandler是当转换完成后将被调用的中断处理函数,用于处理电池电压监测的结果
    hal_gpadc_open(HAL_GPADC_CHAN_BATTERY, HAL_GPADC_ATP_ONESHOT, app_battery_irqhandler);
}
  • 参数/函数讲解
序号参数/函数讲解说明
1hal_gpadc_open()配置 GPADC 通道,以便后续可以使用它来获取电池电压或相关信息,并设置了一个中断处理函数,以便在转换完成时进行相应的处理。

1.2 hal_gpadc_open()

  可以看到 app_battery_irqhandler 钩子函数被赋值给 gpadc_event_cb[channel]这里需要注意一点,用到驱动的地方要加互斥锁。

  • 代码
/**
 * @brief       初始化GPADC并配置指定通道
 * 
 * @param       channel  GPADC通道枚举值,指定要配置的通道
 * @param       atp      GPADC ATP(自动温度补偿)设置
 * @param       cb       GPADC事件回调函数,用于通知测量结果或事件
 * 
 * @return      返回0表示成功,-1表示通道参数错误
 * 
 * 此函数用于打开GPADC的特定通道,进行必要的配置并准备开始数据采集它包括设置数据位,
 * 验证通道参数,设置特定通道的回调和ATP配置,使能相应的中断,以及启动GPADC功能
 */
int hal_gpadc_open(enum HAL_GPADC_CHAN_T channel, enum HAL_GPADC_ATP_T atp, HAL_GPADC_EVENT_CB_T cb)
{
	......
    // NOTE: ADCKEY callback is not set here, but in hal_adckey_set_irq_handler()
    // ADCKEY回调不在这里设置,而在hal_adckey_set_irq_handler()中设置
    if (channel != HAL_GPADC_CHAN_ADCKEY) {
        gpadc_event_cb[channel] = cb;
        gpadc_atp[channel] = atp;
    }
    ......
}

  注意:该函数并不是完整的函数,只截取部分代码

  • 参数/函数讲解
序号参数/函数讲解说明
1int_lock()添加互斥锁
2int_unlock(lock)解锁

  定时调用 app_battery_timer_handler 获取电池的电压值,通过 hal_gpadc_open() 采集完成之后触发中断钩子函数 app_battery_irqhandler()

2 ADC中断

2.1 app_battery_irqhandler()

  • 代码
void app_battery_irqhandler(uint16_t irq_val, HAL_GPADC_MV_T volt)
{
	......
    if (app_battery_measure.index > APP_BATTERY_STABLE_COUNT)
    {
        if (app_battery_measure.cb)
        {
        	if (meanBattVolt>app_battery_measure.highvolt)
            {
                app_battery_measure.cb(APP_BATTERY_STATUS_OVERVOLT, meanBattVolt);
            }
			......
        }
    }

}
  • 参数/函数讲解
序号参数/函数讲解说明
1app_battery_measure.cb电池电量检测钩子函数,在系统初始化阶段已被赋值

  在 adc 采集完成触发中断函数,app_battery_irqhandler() 钩子函数会调用 app_battery_measure.cb 函数,其中根据电压情况传入对应的参数。

2.2 app_battery_event_process()

  在系统初始化阶段的时候,我们可以看到 app_battery_event_process 钩子函数被赋值到 app_battery_measure.cb 中了。

  • 代码
/**
 * 处理应用电池事件
 * 
 * 本函数负责处理电池状态事件,包括设置消息体、设置消息事件并将其放入应用邮箱
 * 
 * @param status 电池状态枚举值,表示当前电池的状态
 * @param volt 电池电压值,以毫伏为单位
 */
static void app_battery_event_process(enum APP_BATTERY_STATUS_T status, APP_BATTERY_MV_T volt)
{
    // 定义一个32位无符号整型变量,用于存储电池事件的消息标识
    uint32_t app_battevt;
    // 定义一个应用消息块结构体变量,用于构造要发送的消息
    APP_MESSAGE_BLOCK msg;

    // 记录电池事件处理的跟踪信息,包括函数名、电池状态和电压
    APP_BATTERY_TRACE(3,"%s %d,%d",__func__, status, volt);

    // 设置消息体的模块ID为电池模块
    msg.mod_id = APP_MODUAL_BATTERY;

    // 构造电池事件的消息内容,包括状态和电压
    APP_BATTERY_SET_MESSAGE(app_battevt, status, volt);

    // 设置消息体的消息ID为构造的电池事件消息标识
    msg.msg_body.message_id = app_battevt;

    // 消息指针设置为NULL,表示没有附加数据需要发送
    msg.msg_body.message_ptr = (uint32_t)NULL;

    // 将构造的消息放入应用的邮箱中,以供后续处理
    app_mailbox_put(&msg);
}
  • 参数/函数讲解
序号函数说明
1APP_BATTERY_SET_MESSAGE()这个宏或函数调用用于设置 app_battevt 变量的值,将电池状态和电压值存储到其中,以便后续构建消息。
2app_mailbox_put()将构建好的消息 msg 放入邮箱中,等待其他模块或线程处理。

  总的来说,这段代码是将电池事件信息封装成消息,并通过邮箱传递给其他模块或线程处理。这里就跟前面创建的邮箱线程关联了起来,这也许就是系统的魅力吧,看似互相独立,但又互相关联。接下来让我们来看看电量状态是怎么传输的吧。

2.3 APP_BATTERY_SET_MESSAGE 和 APP_BATTERY_GET_STATUS

  在 app_battery.cpp 文件头部这里定义了两个宏,分别是 APP_BATTERY_SET_MESSAGEAPP_BATTERY_GET_STATUS,它们的功能如下:

  • 代码
// 定义一个宏,用于设置电池状态消息
// 将电池状态和电压值组合成一个32位的值,并赋给appevt参数
// status: 电池状态,占用16位
// volt: 电池电压,占用16位
#define APP_BATTERY_SET_MESSAGE(appevt, status, volt) (appevt = (((uint32_t)status&0xffff)<<16)|(volt&0xffff))

// 定义一个宏,用于从电池状态消息中获取电池状态
// 从appevt参数中提取电池状态,并赋给status参数
#define APP_BATTERY_GET_STATUS(appevt, status) (status = (appevt>>16)&0xffff)
  • 参数/函数讲解

  (1)APP_BATTERY_SET_MESSAGE(appevt, status, volt)

  这个宏用于将电池状态和电压值组合成一个 uint32_t 类型的事件值。它的参数包括:

序号参数说明
1appevt表示将要设置的事件值。
2status表示电池的状态。
3volt表示电池的电压值。

  这个宏的具体操作是将状态值左移 16 位(使用 (status&0xffff)<<16),然后与电压值进行按位或操作(使用 |(volt&0xffff)),最终将组合好的值赋给 appevt

  (2)APP_BATTERY_GET_STATUS(appevt, status):

  这个宏用于从事件值中提取出电池的状态值。它的参数包括:

序号参数说明
1appevt表示存储了电池状态和电压值的事件值。
2status用于存储提取出的电池状态值。

  这个宏的具体操作是先将事件值右移 16 位(使用 (appevt>>16)),然后再与 0xffff 进行按位与操作,提取出状态值,并将其赋给 status
  这两个宏的作用是在电池事件处理过程中方便地设置和获取电池状态值,提高了代码的可读性和可维护性。

2.4 app_battery_handle_process()

  前面我们知道通过app_set_threadhandle(APP_MODUAL_BATTERY, app_battery_handle_process);app_battery_handle_process 钩子函数注册到邮箱结构 ID(APP_MODUAL_BATTERY) 中。也知道 adc 采集完后通过 app_battery_event_process() 调用 app_mailbox_put() 将电量电压信息发送到邮箱线程中,此时邮箱线程根据对应 ID 调用其钩子函数进行处理消息,而邮箱电量ID的钩子函数就是 app_battery_handle_process()

  • 代码
/**
 * @brief 处理电池状态消息的函数
 * 
 * 根据接收到的电池状态消息,执行相应的处理逻辑。包括处理电池拔出、正常状态和充电状态等不同情况。
 * 如果用户定义了回调函数,在处理完消息后会调用该回调函数通知用户电池状态。
 *
 * @param msg_body 指向包含电池状态消息体的指针
 * @return int 返回0表示处理成功
 */
static int app_battery_handle_process(APP_MESSAGE_BODY *msg_body)
{
    // 定义变量status存储电池状态
    uint8_t status;
    // 定义union变量msg_prams存储电池状态参数
    union APP_BATTERY_MSG_PRAMS msg_prams;

    // 根据消息ID获取电池状态
    APP_BATTERY_GET_STATUS(msg_body->message_id, status);
    // 根据消息ID获取电池状态参数
    APP_BATTERY_GET_PRAMS(msg_body->message_id, msg_prams.prams);

	......
	
	// 触发插拔中断上报状态后,根据充电引脚状态进行处理
    if (status == APP_BATTERY_STATUS_PLUGINOUT){
    	// 启动防抖定时器
        app_battery_pluginout_debounce_start();
    }
    else
    {
    	// 根据当前电池测量状态执行相应处理
        switch (app_battery_measure.status)
        {
            case APP_BATTERY_STATUS_NORMAL:
            	// 电池电量处理 正常模式
                app_battery_handle_process_normal((uint32_t)status, msg_prams);
                break;

            case APP_BATTERY_STATUS_CHARGING:
            	// 电池电量处理 充电模式
                app_battery_handle_process_charging((uint32_t)status, msg_prams);
                break;

            default:
                break;
        }
    }
    .......
}

  注意:该函数并不是完整的函数,只截取部分代码

  • 参数/函数讲解
序号参数说明
1APP_BATTERY_GET_STATUS根据消息ID获取电池状态
2APP_BATTERY_GET_PRAMS根据消息ID获取电池状态参数
3app_battery_pluginout_debounce_start启动电池拔出防抖动处理

3 电池 ADC 采集流程

3.1 整体架构流程图

在这里插入图片描述

3.2 整体架构步骤流程

  至此就大致了解 battery 模块的详细流程:

  Step 1app_battery_open() 配置定时器,初始化电池结构体并注册事件回调和模块处理函数;
  Step 2、定时启动 app_battery_timer_handler() 来通过 adc 采集获取电池的电压值;
  Step 3、采集完成通过中断 app_battery_irqhandler() 将转换之后的电压值与初始值进行比较;
  Step 4、通过 app_battery_event_process() 将不同的电池状态组合成消息发送到邮箱中;
  Step 5、邮箱线程 app_thread 取出消息,并根据对应的 ID 调用其模块的钩子函数 app_battery_handle_process() 进行处理;

请添加图片描述


总结

  感谢观看,这里就是 Battery模块 – 细说 ADC 采集的一次流程的讲解,如果觉得有帮助,请给文章点个赞吧,让更多的人看到。🌹 🌹 🌹

在这里插入图片描述

  也欢迎你,关注我。👍 👍 👍

  原创不易,还希望各位大佬支持一下,你们的点赞、收藏和留言对我真的很重要!!!💕 💕 💕 最后,本文仍有许多不足之处,欢迎各位认真读完文章的小伙伴们随时私信交流、批评指正!下期再见。🎉

更多专栏订阅:



订阅更多,你们将会看到更多的优质内容!!

  • 31
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我是夜阑的狗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值