Funpack5-1 - 用FRDM-MCXA346开发板设计自动追光装置
该项目使用了FRDM-MCXA346开发板、步进电机驱动模块,实现了自动追光的设计,它的主要功能为:控制电机在180度范围内转动,寻找最大光强位置。在寻找过程中通过硅光电池和开发板的ADC功能,实现光强电压到ADC数字的转换,并在TFT显示屏上显示。在完成180度的处理后,控制电机快速回归到最大光强位置。。
标签
参加活动/培训
FRDM-MCXA346
自动追光装置
suncat
更新2026-03-16
14

一、项目介绍

本项目使用恩智浦的FRDM-MCXA346开发板及步进电机驱动板、硅光电池实现对最强光源的追踪。

1.1硬件介绍

本项目使用以下硬件构成:

·FRDM-MCXA346

这是恩智浦公司推出的低成本Freedom 开发板,基于高性能 MCX A346 微控制器(Arm Cortex-M33)。 该开发板提供丰富的板载资源、完整的 Arduino 兼容引脚排列、OpenSDA 调试器,以及多种扩展接口, 是学习嵌入式开发、快速原型设计和产品验证的理想平台。

 

·ULN2003驱动板

用于驱动步进电机。驱动板使用达林顿驱动集成块ULN2003构成,简单实用,输入端兼容单片机数字接口。可以用于低压、简单电机驱动的应用。

 

 

·步进电机

是两相五线步进电机,型号为28BYJ-48,步进角度为1.8度,工作电压5V。

 

·TFT显示屏

用于显示装置工作信息。本项目中使用的是1.8寸的TFT显示屏,SPI接口,分辨率为120*160,驱动核心是ST7735。

 

·太阳能电池

用于实时检测光强。实际上就是一小块太阳能电池板,是从电子玩具上拆下来的器件。

 

·干簧管

用于检测电机的归零位置

 

1.2功能概览

·装置上电

·驱动电机正反转,测试驱动是否有问题

·电机归位

·驱动电机转动,并在转动过程中获取位置的光强,记录最大值。

·完成180度旋转后,回转到光强最大位置处

1.3设计思路

实现功能预览的全部功能,实现步骤如下:

1)准备硬件和软件开发环境

2)连接太阳能电池、步进电机驱动板、TFT显示屏到主控板FRDM-MCXA346上,连接步进电机到步进电机驱动板。

3)编写代码,实现TFT显示屏正常显示;实现对步进电机正反转的驱动;使用MCXA346的ADC功能实现太阳能电池板的电压采集并显示。

4)完成上述功能后,将所有配件组装,做完整测试。

 

功能实现

2.1 装置构成

 

 

2.2软件流程图

 

2.3实现过程

1)TFT显示屏

为了能让TFT显示屏正常显示信息,需要对它进行必要的初始化。这个显示屏使用SPI接口,所以需要主控板FRDM-MCXA346提供必要的GPIO口资源。我按照以下方式设置FRDM-MCXA346开发板和TFT显示屏之间连接

FRDM-MCXA346                TFT显示屏

=======================================

P1_6                         

P1_7                         RESET

P1_3                         CS

P1_1                         SCK

P1_2                         DC

P1_0                         SDA

3V3                          VCC

GND                         GND

3V3                          LED   

=======================================

由于TFT显示屏只使用数据输入,不需要输出,所以J6中的标识为MISO的功能,改用为DC(命令、数据寄存器选择控制线)。

初始化的代码如下:

    // TFT显示屏使用的SPI口用到的GPIO
    //------------------------------------------------------------------------------------------------
    gpio_pin_config_t output_config = {
        .pinDirection = kGPIO_DigitalOutput,
        .outputLogic = 0U
    };
    GPIO_PinInit(GPIO1, PIN_SDO, &output_config); // SDA
    GPIO_PinInit(GPIO1, PIN_SCK, &output_config); // SCK
    GPIO_PinInit(GPIO1, PIN_CS, &output_config); // CS
    GPIO_PinInit(GPIO1, PIN_RS, &output_config); // DC
    GPIO_PinInit(GPIO1, PIN_RST, &output_config); // RESET
 
    const port_pin_config_t OUT = {/* Internal pull-up/down resistor is disabled */
            .pullSelect = kPORT_PullDisable,
            /* Low internal pull resistor value is selected. */
            .pullValueSelect = kPORT_LowPullResistor,
            /* Fast slew rate is configured */
            .slewRate = kPORT_FastSlewRate,
            /* Passive input filter is disabled */
            .passiveFilterEnable = kPORT_PassiveFilterDisable,
            /* Open drain output is disabled */
            .openDrainEnable = kPORT_OpenDrainDisable,
            /* Low drive strength is configured */
            .driveStrength = kPORT_LowDriveStrength,
            /* Normal drive strength is configured */
            .driveStrength1 = kPORT_NormalDriveStrength,
            /* Pin is configured as P3_18 */
            .mux = kPORT_MuxAlt0,
            /* Digital input enabled */
            .inputBuffer = kPORT_InputBufferEnable,
            /* Digital input is not inverted */
            .invertInput = kPORT_InputNormal,
            /* Pin Control Register fields [15:0] are not locked */
            .lockRegister = kPORT_UnlockRegister};
    // P1口和SPI有关的GPIO:P1_0,P1_1,P1_3
    PORT_SetPinConfig(PORT1, PIN_SDO, &OUT);
    PORT_SetPinConfig(PORT1, PIN_SCK, &OUT);
    PORT_SetPinConfig(PORT1, PIN_CS,  &OUT);
    PORT_SetPinConfig(PORT1, PIN_RS,  &OUT);
    PORT_SetPinConfig(PORT1, PIN_RST, &OUT);
    //-------------------------------------------------------------------------------------------------

显示信息使用Gui_DrawFont_GBK16函数。

void Gui_DrawFont_GBK16(uint16_t x, uint16_t y, uint16_t fc, uint16_t bc, uint8_t *s)

形如:

Gui_DrawFont_GBK16(0,0,WHITE,BLACK, "     EETREE     ");

2)太阳能电池电压的检测

太阳能电池电压的检测处理,用到了MCXA346的ADC功能。本项目中使用J6的AN口,即P1_6口。根据数据手册,P1_6可以用作ADC输入,

 

 

因此需要在初始化阶段追加以下设置:

 

   /* ADC0 peripheral is released from reset */
    RESET_ReleasePeripheralReset(kADC0_RST_SHIFT_RSTn);
 
    // ADC采集口P1_6 : ADC0_A22
    const port_pin_config_t port1_6_config = {/* Internal pull-up/down resistor is disabled */
                                                    .pullSelect = kPORT_PullDisable,
                                                    /* Low internal pull resistor value is selected. */
                                                    .pullValueSelect = kPORT_LowPullResistor,
                                                    /* Fast slew rate is configured */
                                                    .slewRate = kPORT_FastSlewRate,
                                                    /* Passive input filter is disabled */
                                                    .passiveFilterEnable = kPORT_PassiveFilterDisable,
                                                    /* Open drain output is disabled */
                                                    .openDrainEnable = kPORT_OpenDrainDisable,
                                                    /* Low drive strength is configured */
                                                    .driveStrength = kPORT_LowDriveStrength,
                                                    /* Normal drive strength is configured */
                                                    .driveStrength1 = kPORT_NormalDriveStrength,
                                                    /* Pin is configured as ADC1_A8 */
                                                    .mux = kPORT_MuxAlt0,
                                                    /* Digital input disabled; it is required for analog functions */
                                                    .inputBuffer = kPORT_InputBufferDisable,
                                                    /* Digital input is not inverted */
                                                    .invertInput = kPORT_InputNormal,
                                                    /* Pin Control Register fields [15:0] are not locked */
                                                    .lockRegister = kPORT_UnlockRegister};
    /* PORT1_10 (pin 3) is configured as ADC0_A22 */
PORT_SetPinConfig(PORT1, 6U, &port1_6_config);

 

并在主程序中做一些特殊处理,

//================================ADC Begin===================================
PRINTF("ADC init\r\n");
 
LPADC_GetDefaultConfig(&mLpadcConfigStruct);
/* Set to highest power level here, users need to properly match ADC clock and power level according
* to application requirements. For specific correspondence, please refer to the data sheet. */
 
mLpadcConfigStruct.powerLevelMode = kLPADC_PowerLevelAlt4;
 
mLpadcConfigStruct.enableAnalogPreliminary = true;
 
mLpadcConfigStruct.referenceVoltageSource = DEMO_LPADC_VREF_SOURCE;
 
 
mLpadcConfigStruct.conversionAverageMode = kLPADC_ConversionAverage128;
 
LPADC_Init(DEMO_LPADC_BASE, &mLpadcConfigStruct);
 
/* Request LPADC calibration. */
LPADC_DoOffsetCalibration(DEMO_LPADC_BASE); /* Request offset calibration, automatic update OFSTRIM register. */
 
/* Request auto calibration (including gain error calibration and linearity error calibration). */
LPADC_DoAutoCalibration(DEMO_LPADC_BASE);
 
/* Set conversion CMD configuration. */
LPADC_GetDefaultConvCommandConfig(&mLpadcCommandConfigStruct);
mLpadcCommandConfigStruct.channelNumber = DEMO_LPADC_USER_CHANNEL;
mLpadcCommandConfigStruct.conversionResolutionMode = kLPADC_ConversionResolutionHigh;
 
LPADC_SetConvCommandConfig(DEMO_LPADC_BASE, DEMO_LPADC_USER_CMDID, &mLpadcCommandConfigStruct);
 
/* Set trigger configuration. */
LPADC_GetDefaultConvTriggerConfig(&mLpadcTriggerConfigStruct);
mLpadcTriggerConfigStruct.targetCommandId = DEMO_LPADC_USER_CMDID;
mLpadcTriggerConfigStruct.enableHardwareTrigger = false;
LPADC_SetConvTriggerConfig(DEMO_LPADC_BASE, 0U, &mLpadcTriggerConfigStruct); /* Configurate the trigger0. */
 
PRINTF("ADC Full Range: %d\r\n", g_LpadcFullRange);
//================================ADC End===================================

 

采集ADC数据,使用以下方式处理:

 

       // 触发ADC
        LPADC_DoSoftwareTrigger(DEMO_LPADC_BASE, 1U); /* 1U is trigger0 mask. */
        // 等待ADC转换完成
        while (!LPADC_GetConvResult(DEMO_LPADC_BASE, &mLpadcResultConfigStruct)) {
        }
        g_adcval = ((mLpadcResultConfigStruct.convValue) >> g_LpadcResultShift);
        g_mapAdcVal = map(g_adcval, 0, 57700, 0, 100);

 

3)驱动步进电机

步进电机需要独立的四条控制线,占用四个GPIO口。初始化代码与驱动LED的方式一致。

 

4)电机归零位置控制

电机转动过程中,通过与转动轴一起运动的磁铁触发常开的干簧管闭合,产生位置归零信号。占用一个GPIO口。初始化代码与驱动LED的方式一致。

三、功能展示

<iframe src="//player.bilibili.com/player.html?isOutside=true&aid=116170929741464&bvid=BV1f1PezWEro&cid=36451846334&p=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"></iframe>

 

四、总结

遇到的问题

1、最开始准备使用MCXA346的SPI外设驱动TFT显示屏,以为与MCXN947应该一样,问题不大。结果调试时除了问题,总也调不通。后来索性改用软件模拟的方式处理。

2、ADC处理部分,原本打算使用中断方式获取数据,但是因为这样做的话,因为驱动电机的步进已经使用了中断,要考虑中断嵌套的问题,处理逻辑会变得复杂,容易引起混乱。所以直接写在主程序的循环中了。

心得体会

在使用FRDM-MCXA346之前,用过FRDM-MCXN947,以为二者应该没有太大的区别。然而实际开发的时候,发现二者的开发包还是不完全一样的,具体体现在对GPIO口、外设的初始化处理上。要想完全掌握,需要用心再学习,不能简单照搬使用。

 

附件下载
frdmmcxa346_motor_gpio_led_output.zip
团队介绍
王贺军,大连伊菲特信息技术有限公司
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号