TI MSPM0G3507开发板光敏电阻传感器(型号5516)驱动移植与光照检测实战

最近在准备一个智能小车的项目,需要检测环境光线来自动控制车灯,正好手头有TI的MSPM0G3507开发板和一块常见的光敏电阻模块。网上资料虽然多,但针对这块新板子的具体教程却很少,自己摸索移植驱动花了不少时间。今天我就把整个从硬件连接到软件编程,再到数据读取的完整过程整理出来,手把手教你怎么在MSPM0G3507上玩转光敏电阻,实现精准的光照检测。无论你是嵌入式新手还是正在备战电赛的同学,跟着做一遍,肯定能搞定。

1. 认识你的硬件:光敏电阻模块与MSPM0开发板

在写代码之前,咱们得先搞清楚要用的两个“主角”是谁,以及它们是怎么工作的。

1.1 光敏电阻模块(型号5516)是什么?

你手里那个小模块,核心是一个叫做光敏电阻的元件,型号通常是5516。你可以把它理解为一个“见光变怂”的电阻。

  • 工作原理:它的内部是硫化镉这类半导体材料。当没有光照射时,内部可自由移动的电荷(载流子)很少,所以电阻非常大,能达到1MΩ(一百万欧姆) 左右,几乎是断路状态。一旦有光照射,光子能量会把更多的电荷“敲”出来,变成可自由移动的载流子,电阻值就会急剧下降。在比较亮的环境下,它的电阻可能只有8KΩ到20KΩ。
  • 模块化设计:为了方便单片机使用,厂家把它做成了一个模块。模块通常会提供两个输出口:
    • AO(模拟量输出):直接输出光敏电阻和另一个固定电阻分压后的电压值。光线越强,电阻越小,分到的电压越低,AO引脚输出电压就越低;反之,光线越暗,输出电压越高。这是一个连续变化的模拟信号。
    • DO(数字量输出):模块上通常还有一个叫LM393的电压比较器芯片。它把AO的电压和一个可调电阻设定的阈值电压进行比较。当光线强于(或弱于)某个设定值时,DO引脚就直接输出一个高电平或低电平的数字信号。你可以通过模块上的电位器旋钮来调节这个触发阈值。

简单说,AO用来做精细的光强测量,DO用来做简单的“亮/暗”开关判断。

模块的基本参数如下,接线时要注意:

参数规格
工作电压3.3V - 5V
工作电流约 1mA
输出信号AO(模拟量),DO(数字量)
接口4 Pin (VCC, GND, DO, AO)

1.2 MSPM0G3507开发板需要做什么?

我们的任务就是让MSPM0开发板读懂这个模块发出的“信号”。

  1. 读取AO(模拟量):需要使用开发板上的ADC(模数转换器) 功能。ADC能把AO引脚上连续的电压值,转换成单片机可以处理的数字值(比如0-4095)。这样我们就能通过这个数字值计算出当前的光照强度百分比。
  2. 读取DO(数字量):这个就简单了,只需要将连接DO引脚的MCU引脚配置为GPIO输入模式,然后读取它的高低电平状态即可。高电平可能代表“过亮”,低电平代表“过暗”(具体取决于模块比较器的设置)。

2. 硬件连接与引脚规划

首先,把模块和开发板用杜邦线连起来。供电和地线一定要接对。

  • 模块 VCC -> 开发板 3.3V 引脚
  • 模块 GND -> 开发板 GND 引脚
  • 模块 AO -> 开发板 PA27 引脚(这是我们计划用于ADC采样的引脚)
  • 模块 DO -> 开发板任意一个GPIO引脚,例如 PA26(用于数字输入)

注意:MSPM0G3507的ADC通道与特定引脚绑定,PA27是其中一个可用的ADC输入引脚(ADC通道0)。选择其他引脚时,务必查阅芯片数据手册,确认该引脚是否支持ADC功能。

3. 软件工程配置与驱动移植

硬件连好了,现在开始在Code Composer Studio (CCS)或你使用的IDE里配置工程。这里以TI推荐的SysConfig图形化配置工具为例,非常直观。

3.1 使用SysConfig配置外设

SysConfig是TI提供的一个图形化配置工具,能自动生成初始化代码,避免了我们手动查寄存器地址的麻烦。

  1. 打开工程,找到配置文件:在你的CCS工程里,找到并双击 empty.syscfg 文件(或其他以.syscfg结尾的配置文件),它会自动打开SysConfig界面。
  2. 添加ADC配置:在界面左侧的“Software”或“Peripherals”栏里,找到并点击 ADC 或 ADC12。点击 ADD 按钮,为工程添加一个ADC实例(例如 ADC12_0)。
  3. 配置ADC通道:
    • 在ADC实例的配置面板中,找到“Channel”或“Input”相关的设置。
    • 选择我们硬件连接的引脚 PA27 对应的ADC通道(例如 ADC12_AIN0 或其他,具体根据芯片手册映射)。
    • 保持其他参数如采样周期、参考电压等为默认值即可,对于光敏电阻测量完全够用。
  4. 添加GPIO配置:同样,在左侧找到 GPIO,添加一个配置。找到我们连接DO引脚的 PA26,将其模式设置为 Input(输入模式)。
  5. 保存并生成代码:点击右上角的 Save 按钮。保存时,如果弹出对话框询问是否生成代码,一定要选择 Yes to All。
  6. 处理可能的编译警告:保存后,IDE可能会自动编译。有时会报一些警告,通常是因为生成了新的文件但包含路径还没更新。先不用管,我们进行下一步。

完成这步后,SysConfig会自动在工程里生成一个 ti_msp_dl_config.h 文件,里面已经定义好了 ADC12_0_INST、GPIO_PORT、GPIO_DO_PIN 这些我们后面代码里要用的标识符。这个文件通常已经被主工程的头文件(如 board.h)包含了,所以我们后续只需要包含 board.h 就行。

3.2 编写光敏电阻驱动文件

现在我们来创建两个文件:bsp_illume.c(驱动源文件)和 bsp_illume.h(驱动头文件)。把它们放到你工程的合适位置,比如 Drivers/BSP 文件夹下。

首先是头文件 bsp_illume.h,它负责声明函数和宏:

#ifndef __BSP_ILLUME_H__
#define __BSP_ILLUME_H__

#include "board.h" // 包含SysConfig生成的定义

// 宏定义:读取DO引脚电平,PA26引脚已在SysConfig中配置为输入
#define GET_DO_IN        DL_GPIO_readPins(GPIOA, GPIO_PIN_26)

// 函数声明
void Illume_Init(void);                      // 初始化ADC
uint32_t Get_Adc_Value(uint8_t Count);       // 获取指定次数的ADC平均值
unsigned int Get_illume_Percentage_value(void); // 获取光照强度百分比
uint8_t Get_DO_In(void);                     // 获取DO引脚数字状态

#endif

接下来是核心的源文件 bsp_illume.c,我逐段解释:

#include "bsp_illume.h"
#include <stdio.h> // 用于printf调试

volatile bool gCheckADC = false; // ADC转换完成标志位,用volatile防止编译器优化

// 初始化函数
void Illume_Init(void)
{
    SYSCFG_DL_init(); // 初始化系统配置,这是TI驱动库要求的

    // 开启ADC的中断,这样ADC转换完成后会触发中断通知我们
    NVIC_EnableIRQ(ADC12_0_INST_INT_IRQN);

    printf("Illume Sensor Init Done!\r\n");
}

这里初始化了系统,并打开了ADC的中断。我们采用“中断”方式来获知ADC转换完成,比一直死等(轮询)更高效。

// 获取单次ADC转换值的函数
uint32_t ADC_GET(void)
{
    unsigned int gAdcResult = 0;
    int timeout = 20000; // 设置一个超时计数器,防止程序卡死

    // 软件触发ADC开始一次转换
    DL_ADC12_startConversion(ADC12_0_INST);

    // 等待ADC转换完成标志位被置位(在中断函数里设置)
    while (false == gCheckADC)
    {
        delay_us(1); // 短暂延时
        timeout--;

        if(timeout <= 0) // 如果超时,报错并退出
        {
            printf("ADC Conversion Timeout Error!\r\n");
            return 0; // 返回0表示错误
        }
    }

    // 从ADC结果存储器中读取通道0的转换值
    gAdcResult = DL_ADC12_getMemResult(ADC12_0_INST, DL_ADC12_MEM_IDX_0);

    // 清除标志位,为下一次转换做准备
    gCheckADC = false;

    return gAdcResult; // 返回12位的ADC原始值(0-4095)
}

这个函数是读取ADC的核心。它启动转换,然后等待中断服务函数告诉我们“转换好了”,最后去取结果。

// 获取多次ADC平均值,用于滤波,使读数更稳定
uint32_t Get_Adc_Value(uint8_t Count)
{
    unsigned int gAdcResult = 0;
    uint8_t i = 0;
    for(i = 0; i < Count; i++)
    {
        gAdcResult += ADC_GET(); // 累加Count次采样值
        delay_ms(1); // 每次采样间隔1ms,避免过于密集
    }
    return (gAdcResult / Count); // 返回平均值
}

// 将ADC值转换为光照强度百分比
unsigned int Get_illume_Percentage_value(void)
{
    // MSPM0G3507的ADC是12位精度,最大值是2^12 - 1 = 4095
    int adc_max = 4095;
    int adc_new = 0;
    int Percentage_value = 0;

    // 获取10次采样的平均值
    adc_new = Get_Adc_Value(10);

    // 核心计算公式:百分比 = (1 - (当前值 / 最大值)) * 100
    // 注意:对于光敏电阻,光线越强,电阻越小,分压越低,ADC值越小。
    // 所以ADC值越小,代表光照越强,百分比应该越高。公式这样设计是合理的。
    Percentage_value = ( 1 - ( (float)adc_new / adc_max ) ) * 100;

    // 确保百分比在0-100之间
    if(Percentage_value > 100) Percentage_value = 100;
    if(Percentage_value < 0) Percentage_value = 0;

    return Percentage_value;
}

// 读取DO引脚的数字状态
uint8_t Get_DO_In(void)
{
    // 直接使用头文件里定义的宏读取引脚电平
    if( GET_DO_IN == 1 )
    {
        return 1; // 返回1,通常可理解为“光线超过阈值”(具体看模块比较器设置)
    }
    return 0; // 返回0,通常可理解为“光线低于阈值”
}

Get_illume_Percentage_value 函数是关键,它把ADC的原始数值转换成了我们直观的0-100%光照强度。这里用了一个技巧:因为光线越强电压越低,ADC值越小,所以用 1 - (adc/max) 来反相,让结果符合“光强越强,百分比越高”的直觉。

// ADC中断服务函数 —— 这个函数名是固定的,由启动文件定义
void ADC12_0_INST_IRQHandler(void)
{
    // 检查是哪个ADC中断源触发了
    switch (DL_ADC12_getPendingInterrupt(ADC12_0_INST))
    {
        // 如果是我们使用的存储器0(对应通道0)转换完成中断
        case DL_ADC12_IIDX_MEM0_RESULT_LOADED:
                gCheckADC = true; // 置位标志位,通知主程序数据准备好了
                break;
        default:
                break;
    }
}

中断函数的名字 ADC12_0_INST_IRQHandler 是TI驱动库约定好的,不能写错。它的作用就是在ADC转换完成后,立刻把 gCheckADC 标志设为 true,这样前面 ADC_GET() 函数里的 while 循环就会结束,继续执行读取结果的代码。

4. 在主函数中测试与验证

驱动写好了,最后就是在主程序里调用它们。修改你的 main.c 或 empty.c 文件:

#include "board.h"
#include <stdio.h>
#include "bsp_illume.h" // 包含我们刚写的驱动头文件

int main(void)
{
    // 开发板基础初始化(时钟、延时等)
    board_init();

    // 初始化光敏电阻模块(主要是ADC)
    Illume_Init();

    while (1)
    {
        // 1. 打印原始的ADC平均值(10次采样)
        printf("ADC Raw Value: %lu\r\n", Get_Adc_Value(10) );

        // 2. 打印计算得到的光照强度百分比
        printf("Light Intensity: %d%%\r\n", Get_illume_Percentage_value() );

        // 3. 打印DO引脚的数字状态
        uint8_t do_state = Get_DO_In();
        if(do_state == 1)
        {
            printf("DO State: BRIGHT (Above Threshold)\r\n");
        }
        else
        {
            printf("DO State: DARK (Below Threshold)\r\n");
        }

        printf("-----------------\r\n");

        // 延时1秒再读
        delay_ms(1000);
    }
}

将代码编译下载到开发板,打开串口调试助手(波特率根据 board_init 里的设置,通常是115200),你就能看到每秒打印一次的数据。用手遮挡光敏电阻,或者用手机闪光灯照射它,观察ADC原始值、百分比和DO状态的变化。

效果应该是这样的:

  • 光线越强,ADC原始值越小,光照强度百分比越接近100%。
  • 光线越暗,ADC原始值越大(接近4095),光照强度百分比越接近0%。
  • 旋转模块上的电位器,可以改变DO输出的阈值点。当光照百分比超过或低于某个值时,DO状态会翻转。

5. 实际使用中的几点心得

  1. ADC值波动:光敏电阻的模拟信号可能会有微小波动,所以驱动里用了 Get_Adc_Value(10) 取10次平均,这是个简单有效的软件滤波方法。如果环境干扰大,可以尝试增加平均次数,或在硬件上在AO引脚对地加一个0.1uF的滤波电容。
  2. 百分比校准:我们的百分比公式 (1 - adc/4095)*100 是一个线性映射。实际上,光敏电阻的阻值变化和光照强度可能不是完全的线性关系。如果项目对精度要求高,可能需要在实际环境中用专业照度计标定几个点,然后采用查表法或拟合公式来计算。
  3. DO阈值的灵活使用:DO引脚提供了一个“硬件比较”的结果,不占用CPU资源。你可以把它直接接到MCU的外部中断引脚上,这样光线一明一暗就能立刻触发中断,非常适合做快速响应,比如检测闪光或物体遮挡。
  4. 供电要稳定:模块和MCU的供电要干净,否则ADC参考电压波动会直接影响测量结果。如果发现数据跳变厉害,检查一下电源。

好了,整个从硬件到软件的流程就走完了。你可以把这个驱动代码用到你的智能灯、自动窗帘或者环境监测项目里。最关键的是理解了AO和DO的区别,以及ADC采样、转换、读取的这个流程。遇到问题,多看看串口打印的数据,调试起来就不难了。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐