Funpack2-2基于英飞凌单片机TC275制作的呼吸灯项目
Funpack第二季第二期:基于英飞凌TC275的串口显示呼吸灯项目,调节电位器可改变呼吸速率
标签
嵌入式系统
MCU
C语言
英飞凌
软件编程
six
更新2022-10-09
河南科技大学
829

Funpack第二季第二期KIT_AURIX_TC275_LITE呼吸灯项目

本次选择的是任务二:

设计一个呼吸灯,通过旋转板卡上的电位计,改变呼吸灯闪烁速率,同时将ADC采集的数据通过串口/CAN,发送到另一台设备上显示

 

一、开发版介绍

KIT_AURIX_TC275_LITE家庭微控制器产品描述AURIX™ TC275 lite 套件配备了基于 32 位单芯片 AurixTM TriCoreTM 的微控制器 AurixTM TC275

FvZgDVKtUVhkwjSR1jxyp190kT5D

从PCB板的布局来看,板载的资源还是挺丰富的,主要包括:

FjAINMY5LVd_rBAx_27UFfzcNbrL

  • 稳压器 5V 至 3.3V
  • 电源指示灯 (D5)
  • LED D1/D2 和 LED3 
  • 电位器 (10 kOhm) 
  • 10 针 DAP 连接器
  • 复位按钮
  • EEPROM 1Kbit

下图是开发板上的器件的结构图

Fj6Be7iWuYuXH0WpXxsY1XKwAZnq

下图是开发板上的电源系统

Fv4-oDAel1OeudKEN8x-oB9DijOA

 

板载的是型号为SK-TC275TP-64的芯片

值得一提的是这块TC275芯片中,有3个核心,为多进程任务提供了运行的基础

主要参数:

具有 200MHz 和 DSP 功能的三重三核(三个高性能 32 位超标量三核 V1.6.1 CPU,在整个汽车温度范围内以 200MHz 运行)
4MB 闪存,带 ECC 保护(每个内核专用紧密耦合的内存区域)
64 KB EEPROM,500 k 周期
472KB RAM,带 ECC 保护
64x DMA 渠道
传感器接口 :10 x发送, 3倍PSI5, 1个PSI5S
最先进的连接性: 1x以太网 100 Mbit , 1个 弹性射线 , 4倍ASCLIN, 4倍QSPI, 1个I²C , 2 倍MSC , 1个HSSL, I²S 仿真 , 5 xCAN 包括数据速率增强型 CAN FD
可编程的 HSM (硬件安全模块)

 

二、开发环境准备

1.AURIX™ Development Studio,用于编程调试下载

2.ComAssistant,用于串口调试

 

三、项目任务的代码实现

      这款开发板配套的例程非常丰富,几乎全部涵盖了所有内部资源的使用,在参看了几个历程后,便完成了此次项目

      首先分析一下任务的需求,(一个呼吸灯,通过旋转板卡上的电位计,改变呼吸灯闪烁速率,同时将ADC采集的数据通过串口/CAN,发送到另一台设备上显示)

      经过思考,判断完成此次任务所需使用的芯片内部资源及完成的功能:需使用ADC功能获取板载电位器的电压值,需使用PWM发生器来产生驱动LED产生呼吸灯的效果,需使用UART功能将ADC采集的数据发送到电脑进行显示,需使用定时器功能来进行各项任务的运行。

      经过查找资料,发现其有非常丰富的历程,每个历程都还有一份配套的文档,可以说是极大程度地降低了入门的难度。

      1.ADC的采集参考ADC_Single_Channel例程

      首先进行初始化配置

/* The VADC module and group are initialized */
/*初始化VADC模块和组*/
void vadcBackgroundScanInit(void)
{

    /* VADC模块配置*/
    /*创建VADC配置*/
    IfxVadc_Adc_Config adcConfig;

    /*使用默认值初始化VADC配置*/
    IfxVadc_Adc_initModuleConfig(&adcConfig, &MODULE_VADC);

    /*使用VADC配置初始化VADC模块*/
    IfxVadc_Adc_initModule(&g_vadcBackgroundScan.vadc, &adcConfig);

    /* VADC组配置*/
    /*创建组配置*/
    IfxVadc_Adc_GroupConfig adcGroupConfig;

    /*使用默认值初始化组配置*/
    IfxVadc_Adc_initGroupConfig(&adcGroupConfig, &g_vadcBackgroundScan.vadc);

    /*定义将使用哪个ADC组*/
    adcGroupConfig.groupId = VADC_GROUP;
    adcGroupConfig.master = VADC_GROUP;

    /*启用后台扫描源*/
    adcGroupConfig.arbiter.requestSlotBackgroundScanEnabled = TRUE;

    /*开启后台自动扫描模式*/
    adcGroupConfig.backgroundScanRequest.autoBackgroundScanEnabled = TRUE;

    /*开启“always”模式(无边缘检测)*/
    adcGroupConfig.backgroundScanRequest.triggerConfig.gatingMode = IfxVadc_GatingMode_always;

    /*使用组配置初始化组*/
    IfxVadc_Adc_initGroup(&g_vadcBackgroundScan.adcGroup, &adcGroupConfig);
}

      配置完成后,启动ADC功能,开始进行转换

/* The input channels to be used are setup and the VADC is set into run mode */
/*要使用的输入通道已设置,VADC设置为运行模式*/
void vadcBackgroundScanRun(void)
{
    /*初始化应用句柄g_vadcBackgroundScan的通道配置,默认值*/
    IfxVadc_Adc_initChannelConfig(&g_vadcBackgroundScan.adcChannelConfig, &g_vadcBackgroundScan.adcGroup);

    g_vadcBackgroundScan.adcChannelConfig.channelId = (IfxVadc_ChannelId)CHANNEL_ID;
    g_vadcBackgroundScan.adcChannelConfig.resultRegister = (IfxVadc_ChannelResult)CHANNEL_RESULT_REGISTER;
    g_vadcBackgroundScan.adcChannelConfig.backgroundChannel = TRUE;

    /*使用通道配置初始化应用程序句柄g_VadcBackgroundScan的通道*/
    IfxVadc_Adc_initChannel(&g_vadcBackgroundScan.adcChannel, &g_vadcBackgroundScan.adcChannelConfig);

    /*启用通道的后台扫描*/
    IfxVadc_Adc_setBackgroundScan(&g_vadcBackgroundScan.vadc,
                                  &g_vadcBackgroundScan.adcGroup,
                                  (1 << (IfxVadc_ChannelId)CHANNEL_ID),
                                  (1 << (IfxVadc_ChannelId)CHANNEL_ID));

    /*启动后台扫描转换*/
    IfxVadc_Adc_startBackgroundScan(&g_vadcBackgroundScan.vadc);
}

      2.串口的使用参考UART_VCOM例程

      首先进行初始化配置

void Init_Uart(void)
{
    /*初始化IfxAsclin_Asc_Config实例,默认值为*/
    IfxAsclin_Asc_Config ascConfig;
    IfxAsclin_Asc_initModuleConfig(&ascConfig, UART_PIN_TX.module);

    /*设置期望的波特率*/
    ascConfig.baudrate.baudrate = SERIAL_BAUDRATE;

    /*ISR优先级和中断目标*/
    ascConfig.interrupt.txPriority = INTPRIO_ASCLIN0_TX;
    ascConfig.interrupt.rxPriority = INTPRIO_ASCLIN0_RX;
    ascConfig.interrupt.typeOfService = IfxCpu_Irq_getTos(IfxCpu_getCoreIndex());

    /*fifo组态*/
    ascConfig.txBuffer = &g_ascTxBuffer;
    ascConfig.txBufferSize = ASC_TX_BUFFER_SIZE;
    ascConfig.rxBuffer = &g_ascRxBuffer;
    ascConfig.rxBufferSize = ASC_RX_BUFFER_SIZE;

    /*端口引脚配置*/
    const IfxAsclin_Asc_Pins pins =
    {
        .cts       = NULL_PTR,
        .ctsMode   = IfxPort_InputMode_noPullDevice,
        .rx        = &UART_PIN_RX,
        .rxMode    = IfxPort_InputMode_noPullDevice,
        .rts       = NULL_PTR,
        .rtsMode   = IfxPort_OutputMode_pushPull,
        .tx        = &UART_PIN_TX,
        .txMode    = IfxPort_OutputMode_pushPull,
        .pinDriver = IfxPort_PadDriver_cmosAutomotiveSpeed1
    };
    ascConfig.pins = &pins;

    IfxAsclin_Asc_initModule(&g_asc, &ascConfig);                       /* Initialize module with above parameters  */
}

      配置完成后,编写串口中断函数,发送/接收个1个,本次只使用了发送,还未使用到接收

IFX_INTERRUPT(asclin0_Tx_ISR, 0, INTPRIO_ASCLIN0_TX);                       /* 添加中断服务例程Adding the Interrupt Service Routine */
void asclin0_Tx_ISR(void)
{
    IfxAsclin_Asc_isrTransmit(&g_asc);
}

IFX_INTERRUPT(asclin0_Rx_ISR, 0, INTPRIO_ASCLIN0_RX);                       /* 添加中断服务例程Adding the Interrupt Service Routine */
void asclin0_Rx_ISR(void)
{
    IfxAsclin_Asc_isrReceive(&g_asc);
}

      再编写数据发送函数,根据例程,该函数传入一字符串,并获取到字符串长度,方可将其正常通过串口进行发送

void send_UART_message(char* str)
{
        Ifx_SizeT str_len = (Ifx_SizeT)strlen(str);
        IfxAsclin_Asc_write(&g_asc, str, &str_len, TIME_INFINITE);
}

      3.PWM发生器的使用参考GTM_ATOM_PWM例程

      同样,首先进行初始化设置

void Init_PWM(void)
{
    IfxGtm_enable(&MODULE_GTM); /* Enable GTM */

    IfxGtm_Cmu_setClkFrequency(&MODULE_GTM, IfxGtm_Cmu_Clk_0, CLK_FREQ);        /* 设置CMU时钟0的频率Set the CMU clock 0 frequency    */
    IfxGtm_Cmu_enableClocks(&MODULE_GTM, IFXGTM_CMU_CLKEN_CLK0);                /* 使能CMU时钟0Enable the CMU clock 0           */

    IfxGtm_Atom_Pwm_initConfig(&g_atomConfig, &MODULE_GTM);                     /* 初始化默认参数Initialize default parameters    */

    g_atomConfig.atom = LED.atom;                                       /* 根据LED选择ATOMSelect the ATOM depending on the LED     */
    g_atomConfig.atomChannel = LED.channel;                             /* 根据LED选择通道Select the channel depending on the LED  */
    g_atomConfig.period = PWM_PERIOD;                                   /* 设置定时器期间Set timer period                         */
    g_atomConfig.pin.outputPin = &LED;                                  /* 设置LED为输出Set LED as output                        */
    g_atomConfig.synchronousUpdateEnabled = TRUE;                       /* 启用同步更新Enable synchronous update                */

    IfxGtm_Atom_Pwm_init(&g_atomDriver, &g_atomConfig);                 /* 初始化脉宽调制Initialize the PWM                       */
    IfxGtm_Atom_Pwm_start(&g_atomDriver, TRUE);                         /* 启动PWM,Start the PWM                            */
}

      编写设置占空比(周期)的函数,传入的是高电平的持续时间,需要使用占空比0-100换算一下

void setDutyCycle(unsigned long dutyCycle)
{
    g_atomConfig.dutyCycle = dutyCycle;                 /* Set duty cycle        */
    IfxGtm_Atom_Pwm_init(&g_atomDriver, &g_atomConfig); /* Re-initialize the PWM */
}

      编写呼吸灯效果函数,PWM_PERIOD为满周期,当占空比为100%时,开始递减,当占空比为0%时,开始递增,每执行一次该函数,便可改变占空比值,从而控制LED的亮度。

void fadeLED(void)
{
    if(g_fadeValue >= PWM_PERIOD)
    {
        g_fadeDir = -1; /* Set the direction of the fade */
    }
    else if(g_fadeValue <= 0)
    {
        g_fadeDir = 1;  /* Set the direction of the fade */
    }
    g_fadeValue += g_fadeDir * FADE_STEP; /* Calculation of the new duty cycle */
    setDutyCycle(g_fadeValue); /* Call the function which is setting the duty cycle of the PWM */
}

      4.定时器的使用参考STM_System_Time例程

      为了确保整个系统已一个相对的时间来运行各个程序,使用定时器来控制时间,当定时时间到后,触发中断便可开始执行,

      使用的是System_Timer(STM),一共有三个定时器可以使用,本次选择了其中的两个,分别以不同的定时时间运行。

      首先是初始化设置

void Init_STM(void)
{
    /* STM0初始化---Initialize time constant */
    g_ticksFor10ms = IfxStm_getTicksFromMilliseconds(BSP_DEFAULT_TIMER, TIMER_INT_TIME);

    IfxStm_initCompareConfig(&g_STMConf);           /* Initialize the configuration structure with default values   */
    g_STMConf.triggerPriority = ISR_PRIORITY_STM;   /* Set the priority of the interrupt                            */
    g_STMConf.typeOfService = IfxSrc_Tos_cpu0;      /* Set the service provider for the interrupts                  */
    g_STMConf.ticks = g_ticksFor10ms;              /* Set the number of ticks after which the timer triggers an
                                                     * interrupt for the first time                                 */
    IfxStm_initCompare(STM, &g_STMConf);            /* Initialize the STM with the user configuration               */


    /* STM1初始化---Initialize time constant */
        g_ticksForLED = IfxStm_getTicksFromMilliseconds(&MODULE_STM1, 500);

        IfxStm_initCompareConfig(&g_STM1Conf);           /* Initialize the configuration structure with default values   */
        g_STM1Conf.triggerPriority = ISR_PRIORITY_STM1;   /* Set the priority of the interrupt                            */
        g_STM1Conf.typeOfService = IfxSrc_Tos_cpu0;      /* Set the service provider for the interrupts                  */
        g_STM1Conf.ticks = g_ticksForLED;              /* Set the number of ticks after which the timer triggers an
                                                         * interrupt for the first time                                 */
        IfxStm_initCompare(STM1, &g_STM1Conf);            /* 使用用户配置初始化STM//Initialize the STM with the user configuration               */

}

      再编写中断服务程序,STM0每10ms1次,主要用于计时

IFX_INTERRUPT(isrSTM, 0, ISR_PRIORITY_STM);

/*中断服务程序*/
void isrSTM(void)
{
    /* Update the compare register value that will trigger the next interrupt */
    /*更新将触发下一个中断的比较寄存器值 */
    IfxStm_increaseCompare(STM, g_STMConf.comparator, g_ticksFor10ms);
    STM_times++;

}

IFX_INTERRUPT(isrSTM1, 0, ISR_PRIORITY_STM1);

/*中断服务程序*/
void isrSTM1(void)
{
    /* Update the compare register value that will trigger the next interrupt */
    /*更新将触发下一个中断的比较寄存器值 */
    IfxStm_increaseCompare(STM1, g_STM1Conf.comparator, g_ticksForLED);

    fadeLED();
}

      想要实现呼吸灯,并且改变呼吸灯速率的效果,就需要控制执行上一步的fadeLED函数执行次数,据此,使用STM1来控制这个次数,编写修改STM1定时时间的函数

void Update_STM1(unsigned int cycle)
{
    g_ticksForLED = IfxStm_getTicksFromMilliseconds(&MODULE_STM1, cycle);
    g_STM1Conf.ticks = g_ticksForLED;              /* Set the number of ticks after which the timer triggers an
                                                     * interrupt for the first time                                 */
    IfxStm_initCompare(STM1, &g_STM1Conf);            /* 使用用户配置初始化STM//Initialize the STM with the user configuration               */
}

      5.主函数部分

      首先是对各个部件进行初始化,在while循环中,判断STM0进入中断的次数(10ms/次),以减少执行的次数,这样每经过50ms就会启动一次ADC转换,并将结果从0-4095换算为5-100(对应0.5s-10s,通过串口将数据发送到电脑,然后判断呼吸灯的周期是否需要改变,若需要,则将其改变,最后重置该中断计次次数,以便进行下一次的判断。

int core0_main(void)
{
    IfxCpu_enableInterrupts();

    /* !!WATCHDOG0 AND SAFETY WATCHDOG ARE DISABLED HERE!!
     * Enable the watch dogs and service them periodically if it is required
     */
    IfxScuWdt_disableCpuWatchdog(IfxScuWdt_getCpuWatchdogPassword());
    IfxScuWdt_disableSafetyWatchdog(IfxScuWdt_getSafetyWatchdogPassword());

    /* Wait for CPU sync event */
    IfxCpu_emitEvent(&g_cpuSyncEvent);
    IfxCpu_waitEvent(&g_cpuSyncEvent, 1);

    Init_Uart();            /* Initialize the module            */
    Init_STM();
    Init_ADC();
    Init_PWM();
    while(1)
    {

        //adc数值越大,周期越大,越慢,0-4095对应,周期500ms-10000ms,单次更新占空比的时间是5-100ms;越小越慢,周期10s
        if (STM_times >=5)
        {
            ADC_Result = ADC_conversion();
            sprintf(Uart_sendstr, "{ADC:%d}\n", (int)ADC_Result);
            send_UART_message(Uart_sendstr);

            PWM_cycle = (ADC_Result*95/4095)+5;
            if(PWM_cycle_last != PWM_cycle)
            {
                Update_STM1(PWM_cycle);
            }
            PWM_cycle_last = PWM_cycle;

            sprintf(Uart_sendstr, "{Cycle:%d}\n", (int)PWM_cycle);
            send_UART_message(Uart_sendstr);
            STM_times = 0;

        }
    }
    return (1);
}

四、功能展示

      使用ComAssistant软件将数据进行可视化显示出来,可以非常直观地看见数据的变化情况

如下图所示

      ADC的值即为经过ADC转换后的数据,Cycle的值为计算出来的呼吸灯周期/100(0.5s-10s)

FjlQz16--7X89s6Ed6MObhdK7ImyFuVTqwoyadRJe-T9Ju5N-rftPMMQ

 

五、对本活动的心得体会

      首先非常高兴能参加此次的活动,感觉本次的任务比较简单,也没有遇到太多的问题,主要也是因为英飞凌提供了非常丰富且详尽的资料及历程,才能让我们迅速上手,也希望以后可以使用到英飞凌的产品。

      

六、参考资料

1.英飞凌官方历程https://github.com/Infineon/AURIX_code_examples

2.AURIX™ Development Studio https://www.infineon.com/cms/en/tools/aurix-tools/free-tools/infineon/

3.CSDN专栏 英飞凌AURIX 牙擦苏-kuan  https://blog.csdn.net/wukuan_123/category_9214281.html

 

附件下载
TC275_Blink.rar
团队介绍
普普通通的在校大学生
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2023 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号