TC275实现任务二呼吸灯【Funpack2-2】
参加Funpack第二季第二期活动,使用TC275开发板实现任务二的呼吸灯,主要完成定时器中断、PWM、ADC、串口通信。
标签
嵌入式系统
测试
数字逻辑
Funpack2-2
硬禾学堂暑假练
ballade
更新2022-10-10
哈尔滨工业大学
753

项目总结报告

一、项目介绍

该项目是硬禾学堂发布的Funpack2-2项目,使用TC275开发板完成一系列任务,我选择完成任务二,设计一个呼吸灯,通过旋转板卡上的电位计,改变呼吸灯闪烁速率,同时将ADC采集的数据通过串口/CAN,发送到另一台设备上显示。我实现以下功能:

1.使用PWM波驱动LED灯,实现不同亮度,然后在定时器中断回调函数里改变PWM占空比,实现呼吸灯;

2.通过ADC模块采样得到电位器的电压值,根据该值大小改变呼吸频率;

3.通过Asclin模块实现串口通信,将PWM的占空比和ADC的采样值传输至电脑上位机显示。

 

功能展示如下:

电位器值较大,呼吸灯频率很快,上位机中蓝色为ADC读数,黄色为呼吸灯PWM占空比值:

FlZ-TLSVz2IfQtcYN148qNwv-Xgp

 

将电位器拧动,使电阻值减小,ADC采样得到的电压值减小,呼吸灯频率减慢:

FuuZsB2vREgU0MnPXpzC-UY807xH

进一步减小电位器阻值,ADC采样值继续减小,呼吸灯频率更慢:

Fl75bWIgR7XnTHeTxyLRdUTvcN1a

 

二、硬件介绍

TC275TP作为第一代 Aurix TC27xT系列产品,专为满足极高的安全标准,同时大幅提高性能而设计。采用创新多核心架构,三个独立的 32 位 TriCore CPU均可工作在200 MHz。可选择多种开发环境,包括Hightec/PLS/Infineon 的基于Eclipse的FreeEntryToolchain,或来自英飞凌基于Eslipse的免费IDE AURIX™ Development Studio,亦或是更多开发工具。

特性:

· 搭载了基于AURIX™ TriCore™ 单片三核微控制器TC275

· 板载Micro USB接口的miniWiggler调试器

· 两个Infineon Shield2Go扩展接口

· 兼容MikroBUS 和Arduino扩展连接

· 带有Infineon新一代CAN 收发器TLE9251VSJ ,可用于汽车和工业应用的HS CAN网络开发

· 已焊接可调旋转电位计,用于评估模拟电压的采集

· 一个用户输入按键

· 预留三个LED可作为工作指示灯

FpJ-_vDg7Pi2AQQmVt0BHf0VLB6I

 

三、代码实现

1.PWM

主要实现初始化函数和设置占空比函数:


/** \brief 初始化指定PWM引脚
 * \param pin PWM引脚
 * \param freq PWM频率
 * \param duty PWM占空比
 * \return 返回HSIC_OK表明初始化成功
 *
 * Coding example:
 * \code
 *    Hsic_pwmInit(IfxGtm_ATOM0_3_TOUT56_P21_5_OUT,1000,0.5);
 * \endcode
 *
 */
hsic_err_t Hsic_pwmInit(IfxGtm_Atom_ToutMap pin, float freq, float duty);

/** \brief 设定占空比
 * \param pin PWM引脚
 * \param duty PWM占空比
 * \return 返回HSIC_OK表明操作成功
 *
 * Coding example:
 * \code
 *    Hsic_pwmSetDuty(IfxGtm_ATOM0_3_TOUT56_P21_5_OUT,0.5);
 * \endcode
 *
 */
hsic_err_t Hsic_pwmSetDuty(IfxGtm_Atom_ToutMap pin, float duty);

 

{
    frequency = IfxGtm_Cmu_getModuleFrequency(gtm);
    IfxGtm_enable(gtm);
    IfxGtm_Cmu_setGclkFrequency(gtm, frequency);
    IfxGtm_Cmu_setClkFrequency(gtm, IfxGtm_Cmu_Clk_0, frequency);
    IfxGtm_Cmu_enableClocks(gtm, IFXGTM_CMU_CLKEN_FXCLK | IFXGTM_CMU_CLKEN_CLK0);
    IfxGtm_Atom_Pwm_Config atomConfig;
    IfxGtm_Atom_Pwm_Driver atomHandle;
    IfxGtm_Atom_Pwm_initConfig(&atomConfig, gtm);
    atomConfig.atom = pin.atom;
    atomConfig.atomChannel  = pin.channel;
    atomConfig.period = (uint32)(frequency / freq);
    atomConfig.dutyCycle = (uint32)(duty * frequency / freq);
    atomConfig.pin.outputPin = &pin;
    atomConfig.synchronousUpdateEnabled = TRUE;
    IfxGtm_Atom_Pwm_init(&atomHandle, &atomConfig);
    IfxGtm_Atom_Pwm_start(&atomHandle, TRUE);
    return HSIC_OK;
}

hsic_err_t Hsic_pwmSetDuty(IfxGtm_Atom_ToutMap pin, float duty)
{
    uint32 period;
    period = IfxGtm_Atom_Ch_getCompareZero(&gtm->ATOM[pin.atom], pin.channel);
    IfxGtm_Atom_Ch_setCompareOneShadow(&gtm->ATOM[pin.atom], pin.channel, (uint32)(duty * period));
    return HSIC_OK;
}

 

2.定时器中断

使用CCU6模块,初始化函数如下:


hsic_err_t Hsic_ccu6TimerIrqInit(hsic_ccu6_t ccu6, hsic_ccu6_timer_t tm, hsic_srctos_t srctos, uint8 prio, uint32 ms)
{
    boolean interrupt_state = disableInterrupts();
    uint64 timer_input_clk;
    uint32 timer_period;
    IfxCcu6_Timer timer;
    IfxCcu6_Timer_Config timerConfig;
    IfxCcu6_Timer_initModuleConfig(&timerConfig, (Ifx_CCU6*)ccu6);
    timer_input_clk = IfxScuCcu_getSpbFrequency();
    uint8 i = 0;
    while(i<16)
    {
        timer_period = (uint32)(timer_input_clk * ms / 1000);
        if(timer_period < 0xffff)   break;
        timer_input_clk >>= 1;
        i++;
    }
    if(16 <= i) return HSIC_ERR_INVALID_ARG;

    switch(tm)
    {
        case TM0:
        {
            if(CCU60 == ccu6)
            {
                timerConfig.interrupt1.typeOfService  = (IfxSrc_Tos)srctos;
                timerConfig.interrupt1.priority       = INT_PRIO_CCU60_TM0;
            }
            else
            {

                timerConfig.interrupt1.typeOfService  = (IfxSrc_Tos)srctos;
                timerConfig.interrupt1.priority       = INT_PRIO_CCU61_TM0;
            }
            timerConfig.timer = IfxCcu6_TimerId_t12;
            timerConfig.interrupt1.source         = IfxCcu6_InterruptSource_t12PeriodMatch;
            timerConfig.interrupt1.serviceRequest = IfxCcu6_ServiceRequest_1;
            timerConfig.base.t12Period            = timer_period;
            timerConfig.base.t12Frequency         = (float)timer_input_clk;
            timerConfig.clock.t12countingInputMode = IfxCcu6_CountingInputMode_internal;
        }break;

        case TM1:
        {
            if(CCU60 == ccu6)
            {
                timerConfig.interrupt2.typeOfService  = (IfxSrc_Tos)srctos;
                timerConfig.interrupt2.priority       = INT_PRIO_CCU60_TM1;
            }
            else
            {
                timerConfig.interrupt2.typeOfService  = (IfxSrc_Tos)srctos;
                timerConfig.interrupt2.priority       = INT_PRIO_CCU61_TM1;
            }
            timerConfig.timer = IfxCcu6_TimerId_t13;
            timerConfig.interrupt2.source         = IfxCcu6_InterruptSource_t13PeriodMatch;
            timerConfig.interrupt2.serviceRequest = IfxCcu6_ServiceRequest_2;
            timerConfig.base.t13Period            = timer_period;
            timerConfig.base.t13Frequency         = (float)timer_input_clk;
            timerConfig.clock.t13countingInputMode = IfxCcu6_CountingInputMode_internal;
        }break;
    }
    timerConfig.timer12.counterValue = 0;
    timerConfig.timer13.counterValue = 0;
    timerConfig.trigger.t13InSyncWithT12 = FALSE;
    IfxCcu6_Timer_initModule(&timer, &timerConfig);
    restoreInterrupts(interrupt_state);
    IfxCcu6_setSuspendMode((Ifx_CCU6*)ccu6, IfxCcu6_SuspendMode_hard);
    IfxCcu6_Timer_start(&timer);
    return HSIC_OK;
}

 

在中断回调函数中获取ADC采样值,根据值的大小设置呼吸的快慢,通过PWM输出:
void CCU60_TM0_CallBack(void)
{
    ADC_value = Hsic_adcGet(IfxVadc_G0_0_AN0_IN);
    float steep = 0.2*ADC_value/(float)4096;
    static float flag = 1;
    duty += flag*steep;
    if(duty>=1)
    {
        flag = -1;
        duty = 1;
    }
    else if(duty<=0)
    {
        flag = 1;
        duty = 0;
    }
    Hsic_pwmSetDuty(IfxGtm_ATOM0_4_TOUT14_P00_5_OUT,duty);
}

 

3.ADC采样

只需实现初始化函数和获取数值的函数:


hsic_err_t Hsic_adcInit(IfxVadc_Vadcg_In pin)
{
    IfxVadc_Adc_ChannelConfig adcChannelConfig;
    IfxVadc_Adc_Channel adcChannel;
    if(vadc.vadc!=NULL) goto INITADCGROUP;
    IfxVadc_Adc_Config adcConfig;
    IfxVadc_Adc_initModuleConfig(&adcConfig, &MODULE_VADC);
    IfxVadc_Adc_initModule(&vadc, &adcConfig);
INITADCGROUP:
    if(adcGroup[pin.groupId].group!=NULL) goto INITADCCH;
    IfxVadc_Adc_GroupConfig adcGroupConfig;
    IfxVadc_Adc_initGroupConfig(&adcGroupConfig, &vadc);
    adcGroupConfig.groupId = pin.groupId;
    adcGroupConfig.master = pin.groupId;
    adcGroupConfig.arbiter.requestSlotQueueEnabled          = TRUE;
    adcGroupConfig.arbiter.requestSlotScanEnabled           = TRUE;
    adcGroupConfig.arbiter.requestSlotBackgroundScanEnabled = TRUE;
    adcGroupConfig.queueRequest.triggerConfig.gatingMode          = IfxVadc_GatingMode_always;
    adcGroupConfig.scanRequest.triggerConfig.gatingMode           = IfxVadc_GatingMode_always;
    adcGroupConfig.backgroundScanRequest.triggerConfig.gatingMode = IfxVadc_GatingMode_always;
    adcGroupConfig.scanRequest.autoscanEnabled = TRUE;
    adcGroupConfig.backgroundScanRequest.autoBackgroundScanEnabled = TRUE;
    IfxVadc_Adc_initGroup(&adcGroup[pin.groupId], &adcGroupConfig);
INITADCCH:
    IfxVadc_Adc_initChannelConfig(&adcChannelConfig, &adcGroup[pin.groupId]);
    adcChannelConfig.channelId = pin.channelId;
    adcChannelConfig.resultRegister = (IfxVadc_ChannelResult)pin.groupId;
    adcChannelConfig.backgroundChannel = TRUE;
    IfxVadc_Adc_initChannel(&adcChannel,&adcChannelConfig);
    unsigned channels = (1 << adcChannelConfig.channelId);
    unsigned mask     = channels;
    IfxVadc_Adc_setBackgroundScan(&vadc, &adcGroup[pin.groupId], channels, mask);
    IfxVadc_Adc_startBackgroundScan(&vadc);
    return HSIC_OK;
}

uint16 Hsic_adcGet(IfxVadc_Vadcg_In pin)
{
    while(IfxVadc_getScanStatus(&pin.module->G[pin.groupId])==IfxVadc_Status_channelsStillPending);
    Ifx_VADC_RES res = IfxVadc_getResult(&pin.module->G[pin.groupId],pin.channelId);
    return (res.B.RESULT&0x0fff);
}

 

4.UART串口通信

使用Asclin模块,初始化函数:


hsic_err_t Hsic_uartInit(IfxAsclin_Tx_Out tx, IfxAsclin_Rx_In rx, uint32 baudrate, hsic_srctos_t srctos)
{
    if(tx.module!=rx.module)return HSIC_ERR_INVALID_ARG;
    uint8 i = 0xff&(((uint32)rx.module - (uint32)&MODULE_ASCLIN0)>>8);
    IfxAsclin_Asc_Config ascConfig;
    IfxAsclin_Asc_initModuleConfig(&ascConfig, tx.module);
    ascConfig.baudrate.prescaler = 1;
    ascConfig.baudrate.baudrate = (float32)baudrate;
    // ISR priorities and interrupt target
    if(i==0)
    {
        ascConfig.interrupt.txPriority = ASCLIN0_TX_INT_PRIO;
        ascConfig.interrupt.rxPriority = ASCLIN0_RX_INT_PRIO;
        ascConfig.interrupt.erPriority = ASCLIN0_ER_INT_PRIO;
    }
    else if(i==1)
    {
        ascConfig.interrupt.txPriority = ASCLIN1_TX_INT_PRIO;
        ascConfig.interrupt.rxPriority = ASCLIN1_RX_INT_PRIO;
        ascConfig.interrupt.erPriority = ASCLIN1_ER_INT_PRIO;
    }
    else if(i==2)
    {
        ascConfig.interrupt.txPriority = ASCLIN2_TX_INT_PRIO;
        ascConfig.interrupt.rxPriority = ASCLIN2_RX_INT_PRIO;
        ascConfig.interrupt.erPriority = ASCLIN2_ER_INT_PRIO;
    }
    else if(i==3)
    {
        ascConfig.interrupt.txPriority = ASCLIN3_TX_INT_PRIO;
        ascConfig.interrupt.rxPriority = ASCLIN3_RX_INT_PRIO;
        ascConfig.interrupt.erPriority = ASCLIN3_ER_INT_PRIO;
    }
    else
    {
        return HSIC_ERR_INVALID_ARG;
    }
    ascConfig.interrupt.typeOfService =   (IfxSrc_Tos)srctos;
    // FIFO configuration
    ascConfig.txBuffer = &ascTxBuffer[i][0];
    ascConfig.txBufferSize = ASC_TX_BUFFER_SIZE;
    ascConfig.rxBuffer = &ascRxBuffer[i][0];
    ascConfig.rxBufferSize = ASC_RX_BUFFER_SIZE;
    // pin configuration
    const IfxAsclin_Asc_Pins pins = {
        NULL,                           IfxPort_InputMode_pullUp,    // CTS pin not used
        &rx,   IfxPort_InputMode_pullUp,    // Rx pin
        NULL,                           IfxPort_OutputMode_pushPull, // RTS pin not used
        &tx,   IfxPort_OutputMode_pushPull, // Tx pin
        IfxPort_PadDriver_cmosAutomotiveSpeed1
    };
    ascConfig.pins = &pins;
    IfxAsclin_Asc_initModule(&asc[i], &ascConfig);
    return HSIC_OK;

}

 

发送数据函数:

void Hsic_VarUpload(float *my_var, uint8 var_num, uint8 ascnum)
{
    uint8 cmdf[7] =
    { 0x55, 0xaa, 0x11, 0x55, 0xaa, 0xff, 0x01 };
    uint8 cmdr = 0x01;
    uint8 begin_cmd[3] =
    { 0x55, 0xaa, 0x11 };
    /*! 发送帧头 */
    Hsic_uartWrite(begin_cmd, sizeof(begin_cmd), ascnum);
    /*! 发送数据个数 */
    Hsic_uartWrite(cmdf, sizeof(cmdf), ascnum);
    Hsic_uartWrite(&var_num, 1, ascnum);
    /*! 发送数据 */
    Hsic_uartWrite((uint8* )(my_var), var_num * 4U, ascnum);
    /*! 发送帧尾 */
    Hsic_uartWrite(&cmdr, 1, ascnum);
}

 

四、遇到的问题

TC275的库和手册只有全英文的,阅读比较费力;其定时器的实现方法有很多,用CCU6模块只是其中之一,十分容易搞混。

Tricore架构和ARM不同,需要一段时间适应。

 

五、心得体会

这次使用的芯片较为冷门,中文资料较少,好在iLLD库中注释较为齐全,可以让我们体会不同架构的单片机。

附件下载
test.rar
项目工程文件夹压缩包
团队介绍
吴子蕤
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2023 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号