本帖最后由 suncat0504 于 2026-7-20 16:35 编辑
本次电机月活动中我报名参加了,参加的项目是使用FRDM-MCXC444开发板制作《温控自动摇头桌面风扇》。 这个风扇的制作,在我看来,需要两个关键点: 1、量化温度数据 2、使用量化的温度数据,改变PWM的占空比,控制风扇的转速。 所以当收到FRDM-MCXC444开发板后,第一件事儿是就是熟悉这个开发板的开发IDE。因为是恩智浦的开发板,毫无疑问使用恩智浦自己的IDE是最快、最好的选择。 在这个IDE中提供了Installed SDKs功能,可以从官网快速安装指定型号的开发板对应的SDK。安装好SDK,可以使用“Import SDK example(s)”功能导入学习例程。 我从例程库中导入frdmmcxc444_tpm_simple_pwm例程。这个例程提供了一个产生PWM信号的例子,可以直接拿来用。我初步打算在此基础上做修改,并加上温度采集处理,利用温度值控制PWM的占空比,控制风扇的转速。 测试的第一步是先熟悉PWM程序。这个例程的主程序: - int main(void) {
- tpm_config_t tpmInfo; // TPM模块配置结构体
- tpm_chnl_pwm_signal_param_t tpmParam; // PWM通道参数结构体
- uint8_t control; // 用于保存通道控制寄存器的原始值
- // 初始化板级硬件(时钟、引脚、调试串口、PWM输出引脚的复用功能配置等)
- BOARD_InitHardware();
- PRINTF("MCUX SDK version: %s\r\n", MCUXSDK_VERSION_FULL_STR);
- /* Print a note to terminal */
- PRINTF("\r\nTPM example to output center-aligned PWM signal\r\n");
- PRINTF(
- "\r\nIf an LED is connected to the TPM pin, you will see a change in LED brightness if you enter different "
- "values");
- PRINTF(
- "\r\nIf no LED is connected to the TPM pin, then probe the signal using an oscilloscope");
- // 获取默认配置
- TPM_GetDefaultConfig(&tpmInfo);
- // 根据目标PWM频率(DEMO_PWM_FREQUENCY)和TPM模块的输入时钟(TPM_SOURCE_CLOCK),
- // 自动计算出一个合适的时钟分频系数(prescale),确保计数器能精确产生所需的频率。
- tpmInfo.prescale = TPM_CalculateCounterClkDiv(BOARD_TPM_BASEADDR, DEMO_PWM_FREQUENCY, TPM_SOURCE_CLOCK);
- // 将配置写入硬件寄存器,启动TPM模块(但此时定时器还未开始计数)
- TPM_Init(BOARD_TPM_BASEADDR, &tpmInfo);
- /* Configure tpm params with frequency 24kHZ */
- // 指定通道(对应GPIO哪个引脚)
- tpmParam.chnlNumber = (tpm_chnl_t) BOARD_TPM_CHANNEL;
- // 定义"有效电平"(高电平有效或低电平有效)
- tpmParam.level = TPM_LED_ON_LEVEL;
- // 初始占空比(全局变量,最开始0%)
- tpmParam.dutyCyclePercent = updatedDutycycle;
- if (kStatus_Success != TPM_SetupPwm(BOARD_TPM_BASEADDR, &tpmParam, 1U, kTPM_CenterAlignedPwm, DEMO_PWM_FREQUENCY, TPM_SOURCE_CLOCK)) {
- PRINTF("\r\nSetup PWM fail!\r\n");
- return -1;
- }
- // 开始运行TPM计数器,PWM信号正式开始在引脚上输出
- TPM_StartTimer(BOARD_TPM_BASEADDR, kTPM_SystemClock);
- // 获取当前通道的控制寄存器值
- control = TPM_GetChannelContorlBits(BOARD_TPM_BASEADDR, (tpm_chnl_t) BOARD_TPM_CHANNEL);
- while (1) {
- //updatedDutycycle = getCharValue * 10U;
- // 每1000一个等级
- cnt = (cnt+1)% (99 * duan + 1);
- if ((cnt/duan) != oldDutycycle) {
- // 保存本次占空比
- oldDutycycle = cnt/duan;
- // 占空比以10个单位改变,避免太频繁,导致闪烁
- if ((oldDutycycle%seg) == 0) {
- // 禁用通道输出(避免更新过程中产生毛刺)
- TPM_DisableChannel(BOARD_TPM_BASEADDR, (tpm_chnl_t) BOARD_TPM_CHANNEL);
- // 更新占空比
- if (kStatus_Success == TPM_UpdatePwmDutycycle(BOARD_TPM_BASEADDR, (tpm_chnl_t) BOARD_TPM_CHANNEL, kTPM_CenterAlignedPwm, oldDutycycle)) {
- PRINTF("The duty cycle was successfully updated! %d, %d \r\n", cnt, oldDutycycle);
- }
- // 开通道,使更新后占空比体现在通道(引脚PTD5)上
- TPM_EnableChannel(BOARD_TPM_BASEADDR, (tpm_chnl_t) BOARD_TPM_CHANNEL, control);
- }
- }
- }
- }
复制代码
根据代码和电路原理图, 程序运行后,PWN的输出信号由J2的PTD5引脚输出,同时板载的绿色LED会根据PWM的占空比调整亮度。改变占空比需要通过串口输入“0” - “9“的字符实现,分别对应0 - 90%的占空比,数值越大,亮度越低。 在此程序的基础上做简单修改,就可以改成呼吸灯中的渐灭方式的处理模式。 - int main(void) {
- tpm_config_t tpmInfo; // TPM模块配置结构体
- tpm_chnl_pwm_signal_param_t tpmParam; // PWM通道参数结构体
- uint8_t control; // 用于保存通道控制寄存器的原始值
- // 初始化板级硬件(时钟、引脚、调试串口、PWM输出引脚的复用功能配置等)
- BOARD_InitHardware();
- PRINTF("MCUX SDK version: %s\r\n", MCUXSDK_VERSION_FULL_STR);
- /* Print a note to terminal */
- PRINTF("\r\nTPM example to output center-aligned PWM signal\r\n");
- PRINTF(
- "\r\nIf an LED is connected to the TPM pin, you will see a change in LED brightness if you enter different "
- "values");
- PRINTF(
- "\r\nIf no LED is connected to the TPM pin, then probe the signal using an oscilloscope");
- // 获取默认配置
- TPM_GetDefaultConfig(&tpmInfo);
- // 根据目标PWM频率(DEMO_PWM_FREQUENCY)和TPM模块的输入时钟(TPM_SOURCE_CLOCK),
- // 自动计算出一个合适的时钟分频系数(prescale),确保计数器能精确产生所需的频率。
- tpmInfo.prescale = TPM_CalculateCounterClkDiv(BOARD_TPM_BASEADDR, DEMO_PWM_FREQUENCY, TPM_SOURCE_CLOCK);
- // 将配置写入硬件寄存器,启动TPM模块(但此时定时器还未开始计数)
- TPM_Init(BOARD_TPM_BASEADDR, &tpmInfo);
- /* Configure tpm params with frequency 24kHZ */
- // 指定通道(对应GPIO哪个引脚)
- tpmParam.chnlNumber = (tpm_chnl_t) BOARD_TPM_CHANNEL;
- // 定义"有效电平"(高电平有效或低电平有效)
- tpmParam.level = TPM_LED_ON_LEVEL;
- // 初始占空比(全局变量,最开始0%)
- tpmParam.dutyCyclePercent = updatedDutycycle;
- if (kStatus_Success != TPM_SetupPwm(BOARD_TPM_BASEADDR, &tpmParam, 1U, kTPM_CenterAlignedPwm, DEMO_PWM_FREQUENCY, TPM_SOURCE_CLOCK)) {
- PRINTF("\r\nSetup PWM fail!\r\n");
- return -1;
- }
- // 开始运行TPM计数器,PWM信号正式开始在引脚上输出
- TPM_StartTimer(BOARD_TPM_BASEADDR, kTPM_SystemClock);
- // 获取当前通道的控制寄存器值
- control = TPM_GetChannelContorlBits(BOARD_TPM_BASEADDR, (tpm_chnl_t) BOARD_TPM_CHANNEL);
- while (1) {
- // 每1000一个等级
- cnt = (cnt+1)% (99 * duan + 1);
- if ((cnt/duan) != oldDutycycle) {
- // 保存本次占空比
- oldDutycycle = cnt/duan;
- // 占空比以10个单位改变,避免太频繁,导致闪烁
- if ((oldDutycycle%seg) == 0) {
- // 禁用通道输出(避免更新过程中产生毛刺)
- TPM_DisableChannel(BOARD_TPM_BASEADDR, (tpm_chnl_t) BOARD_TPM_CHANNEL);
- // 更新占空比
- if (kStatus_Success == TPM_UpdatePwmDutycycle(BOARD_TPM_BASEADDR, (tpm_chnl_t) BOARD_TPM_CHANNEL, kTPM_CenterAlignedPwm, oldDutycycle)) {
- PRINTF("The duty cycle was successfully updated! %d, %d \r\n", cnt, oldDutycycle);
- }
- // 开通道,使更新后占空比体现在通道(引脚PTD5)上
- TPM_EnableChannel(BOARD_TPM_BASEADDR, (tpm_chnl_t) BOARD_TPM_CHANNEL, control);
- }
- }
- }
- }
复制代码
运行效果:
|