1 项目描述
本次参加的是Funpack第二季第二期基于英飞凌的AurixTC275的一个开发板。这次选择的任务是实现任务2目标是设计一个呼吸灯,通过旋转板卡上的电位计改变呼吸灯的闪烁速率,同时将ADC采集的数据通过串口发送到PC机上。
那么根据实现任务我们可以把目标拆解成3个部分,第一部分是基于pwm的一个呼吸灯的实现;然后是旋转板卡电位计这部分是通过ADC去采集电位器的一个电压;最后第三部分是ADC采集数据的一个上传,这部分是通过串口上传到PC机并在PC的串口助手进行显示。
2 功能模块实现
2.1LED小灯驱动
项目共用到2个LED小灯,分别用闪烁频率和光的亮度来对应电位计的电压。LED1引脚的状态由GTM的TOM定时器产生的PWM信号控制,LED2是通过CPU1控制电平翻转。GTM TOM用于产生PWM信号,用来驱动LED的发光强度。
通用定时器模块(GTM)是一个模块化的定时器单元,它有一个内置的定时器输出模块(TOM),可以提供多达16个独立通道来生成输出信号。时钟管理单元(CMU)负责GTM的时钟生成。固定时钟生成单元(FXU)是它的子单元之一,它为GTM模块提供了五个预定义的不可配置时钟,包括TOM。
FXU时钟0频率(ffxclk0)为100mhz。所需的周期值PWM频率(fPWM)的计算公式如下:
𝑃𝑒𝑟𝑖𝑜𝑑 =𝑓𝑓𝑥𝑐𝑙𝑘0/𝑓𝑃𝑊𝑀;
void initGtmTomPwm(void)
{
IfxGtm_enable(&MODULE_GTM); /* Enable GTM */
IfxGtm_Cmu_enableClocks(&MODULE_GTM, IFXGTM_CMU_CLKEN_FXCLK); /* Enable the FXU clock */
/* Initialize the configuration structure with default parameters */
IfxGtm_Tom_Pwm_initConfig(&g_tomConfig, &MODULE_GTM);
g_tomConfig.tom = LED.tom; /* Select the TOM depending on the LED */
g_tomConfig.tomChannel = LED.channel; /* Select the channel depending on the LED */
g_tomConfig.period = PWM_PERIOD; /* Set the timer period */
g_tomConfig.pin.outputPin = &LED; /* Set the LED port pin as output */
g_tomConfig.synchronousUpdateEnabled = TRUE; /* Enable synchronous update */
IfxGtm_Tom_Pwm_init(&g_tomDriver, &g_tomConfig); /* Initialize the GTM TOM */
IfxGtm_Tom_Pwm_start(&g_tomDriver, TRUE); /* Start the PWM */
}
/* This function sets the duty cycle of the PWM */
void setDutyCycle(uint32 dutyCycle)
{
g_tomConfig.dutyCycle = dutyCycle; /* Change the value of the duty cycle */
IfxGtm_Tom_Pwm_init(&g_tomDriver, &g_tomConfig); /* Re-initialize the PWM */
}
void fadeLED_ByVoltage(uint32 Voltage)
{
g_fadeValue = (0x1000-Voltage)*(PWM_PERIOD/0x1000); /* Calculation of the new duty cycle */
setDutyCycle(g_fadeValue); /* Set the duty cycle of the PWM */
}
2.2电压采集ADC模块
ADC的输入值由电路板上的电位器决定,改变电位计旋钮即可改变电压值。电压的调节范围为0-3.3V。
AURIX™微控制器提供许多模拟输入通道(每个ADC最多8个)可以l连接到ADC模块,使用逐次逼近寄存器(SAR)原理。
使用ADC_Single_Channel.h中定义的应用程序数据结构,实例化一个名为g_vadcBackgroundScan from type的全局对象ApplicationVadcBackgroundScan。配置VADC以后台扫描模式运行,连续转换模拟输入通道值。
/* This function retrieves the conversion value and indicates it by LEDs */
void indicateConversionValue(void)
{
Ifx_VADC_RES conversionResult;
/* Retrieve the conversion value until valid flag of the result register is true */
do
{
conversionResult = IfxVadc_Adc_getResult(&g_vadcBackgroundScan.adcChannel);
}
while (!conversionResult.B.VF);
IfxAsclin_Asc_print("The current voltage: %.2f\r\n", conversionResult.B.RESULT*3.3/4096.0);
fadeLED_ByVoltage( conversionResult.B.RESULT);
WAIT_TIME = 30+(1000-30)*(1-conversionResult.B.RESULT/4096.0);
g_ticksFor1s = IfxStm_getTicksFromMilliseconds(BSP_DEFAULT_TIMER, WAIT_TIME);
}
/* The VADC module and group are initialized */
void vadcBackgroundScanInit(void)
{
/* VADC module configuration */
/* Create VADC configuration */
IfxVadc_Adc_Config adcConfig;
/* Initialize the VADC configuration with default values */
IfxVadc_Adc_initModuleConfig(&adcConfig, &MODULE_VADC);
/* Initialize the VADC module using the VADC configuration */
IfxVadc_Adc_initModule(&g_vadcBackgroundScan.vadc, &adcConfig);
/* VADC group configuration */
/* Create group configuration */
IfxVadc_Adc_GroupConfig adcGroupConfig;
/* Initialize the group configuration with default values */
IfxVadc_Adc_initGroupConfig(&adcGroupConfig, &g_vadcBackgroundScan.vadc);
/* Define which ADC group is going to be used */
adcGroupConfig.groupId = VADC_GROUP;
adcGroupConfig.master = VADC_GROUP;
/* Enable background scan source */
adcGroupConfig.arbiter.requestSlotBackgroundScanEnabled = TRUE;
/* Enable background auto scan mode */
adcGroupConfig.backgroundScanRequest.autoBackgroundScanEnabled = TRUE;
/* Enable the gate in "always" mode (no edge detection) */
adcGroupConfig.backgroundScanRequest.triggerConfig.gatingMode = IfxVadc_GatingMode_always;
/* Initialize the group using the group configuration */
IfxVadc_Adc_initGroup(&g_vadcBackgroundScan.adcGroup, &adcGroupConfig);
}
/* The input channels to be used are setup and the VADC is set into run mode */
void vadcBackgroundScanRun(void)
{
/* Initialize the channel configuration of application handle g_vadcBackgroundScan with default values */
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;
/* Initialize the channel of application handle g_VadcBackgroundScan using the channel configuration */
IfxVadc_Adc_initChannel(&g_vadcBackgroundScan.adcChannel, &g_vadcBackgroundScan.adcChannelConfig);
/* Enable background scan for the channel */
IfxVadc_Adc_setBackgroundScan(&g_vadcBackgroundScan.vadc,
&g_vadcBackgroundScan.adcGroup,
(1 << (IfxVadc_ChannelId)CHANNEL_ID),
(1 << (IfxVadc_ChannelId)CHANNEL_ID));
/* Start background scan conversion */
IfxVadc_Adc_startBackgroundScan(&g_vadcBackgroundScan.vadc);
}
2.3 UART数据传输模块
采集到的电压值经过转换通过UART从设备发送到PC。然后在串行监视器中显示出来。
用于UART通信的ASCLIN模块的配置方法是通过函数IfxAsclin_Asc_initModuleConfig()使用默认值初始化IfxAsclin_Asc_Config结构的实例。
void init_UART(void)
{
/* Initialize an instance of IfxAsclin_Asc_Config with default values */
IfxAsclin_Asc_Config ascConfig;
IfxAsclin_Asc_initModuleConfig(&ascConfig, SERIAL_PIN_TX.module);
/* Set the desired baud rate */
ascConfig.baudrate.baudrate = SERIAL_BAUDRATE;
/* ISR priorities and interrupt target */
ascConfig.interrupt.txPriority = INTPRIO_ASCLIN0_TX;
ascConfig.interrupt.typeOfService = IfxCpu_Irq_getTos(IfxCpu_getCoreIndex());
/* FIFO configuration */
ascConfig.txBuffer = &g_ascTxBuffer;
ascConfig.txBufferSize = ASC_TX_BUFFER_SIZE;
/* Port pins configuration */
const IfxAsclin_Asc_Pins pins =
{
NULL_PTR, IfxPort_InputMode_pullUp, /* CTS pin not used */
&SERIAL_PIN_RX, IfxPort_InputMode_pullUp, /* RX pin not used */
NULL_PTR, IfxPort_OutputMode_pushPull, /* RTS pin not used */
&SERIAL_PIN_TX, IfxPort_OutputMode_pushPull, /* TX pin */
IfxPort_PadDriver_cmosAutomotiveSpeed1
};
ascConfig.pins = &pins;
IfxAsclin_Asc_initModule(&g_asc, &ascConfig); /* Initialize module with above parameters */
}
void send_UART_message(void)
{
uint8 txData[] = "Hello World!"; /* Message to send */
Ifx_SizeT count = 12; /* Size of the message */
IfxAsclin_Asc_write(&g_asc, txData, &count, TIME_INFINITE); /* Transfer of data */
}
#include "_Utilities/Ifx_Assert.h"
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
void IfxAsclin_Asc_print(pchar format, ...)
{
if (1)
{
char message[STDIF_DPIPE_MAX_PRINT_SIZE + 1];
Ifx_SizeT count;
va_list args;
va_start(args, format);
vsprintf((char *)message, format, args);
va_end(args);
count = (Ifx_SizeT)strlen(message);
IFX_ASSERT(IFX_VERBOSE_LEVEL_ERROR, count < STDIF_DPIPE_MAX_PRINT_SIZE);
//return
// IfxStdIf_DPipe_write(stdIf, (void *)message, &count, TIME_INFINITE);
IfxAsclin_Asc_write(&g_asc, message, &count, TIME_INFINITE); /* Transfer of data */
}
else
{
//return TRUE;
}
}
使用以下图标在AURIX™开发工作室中打开UART串口监视器,查看上传的数据。
3 实验现象
旋转电位器可以看到电压的升以及看到PC上串口助手的数值在升高,反向调节旋钮可以看到PC上传的电压数值在降低。
两个LED小灯的变化,是下方的小灯LED1是通过pwm信号驱动所以led的亮度对应着电压的高低,上方的LED是通过定时器进行电平翻转,小灯闪烁的频率对应电压的高低。
4 心得体会:
任务2的实现是在几个Demo例程的基础上进行开发的,因为有了官方的相关例程做铺垫而且官方的例程都配备对应的说明文档,所以整体实现起来难度并不是很大。通过本次项目了解到了英飞凌TC275这款MCU的的体系结构以及相关的开发流程,当然除此之外个人感觉更有意义的是在本次项目的实现过程中或多或少的有了解到一些车规级的MCU相关知识点,比如VADC与DSADC之间的使用及其区别、CCU6 , GTM, GPT12中的pwm区别等等...
参考链接:
- AURIX™ Development Studio 安装使用
- AURIXTM系列产品的开发案例
- AURIX中两个模块VADC与DSADC之间的使用及其区别是什么
- TC234芯片中的CCU6 , GTM, GPT12中的pwm区别
- ADC_Single_Channel_1_KIT_TC275_LK
- UART_VCOM_1_KIT_TC275_LK
- GTM_TOM_PWM