智能车竞赛:Infineon TC264单片机使用总结快速入门

news2025/7/10 3:34:29

本文主要是为了备赛第十八届全国大学生智能车竞赛,基于逐飞开源库和芯片数据手册的一些学习总结,使用英飞凌官方的AURIX Development Studio开发环境。

正如STM32的开发方式有标准库和HAL库,Infineon单片机也有官方库,而逐飞开源库则是在官方库的基础上又封装了一层,变成了易使用、易理解的API,极大的方便我们调用和编写程序。

那么对于智能车比赛,必须熟练掌握的内容有:GPIO、定时器、(外部中断)、中断函数入口和优先级、串口的发送与接收、如何产生PWM、ADC、如何读取正交编码器

目录

GPIO使用——点灯与按键检测

PIT产生简单的定时中断

中断函数入口和优先级

串口的收发——接收数据并解析(上位机调试)

PWM的产生——以呼吸灯为例


GPIO使用——点灯与按键检测

由芯片参考手册可知,TC264的GPIO端口号并不是连续的,每个端口号的引脚数目也不相同。但是在逐飞库中每个端口号都定义了16个引脚。

特别提醒:在设置IO时请自行根据硬件确认当前芯片是否具有此IO

需要注意仅P20_2是不能用于输出的,仅仅只有输入的功能

TC264DA芯片的21.6无法正常使用。这点是逐飞开源库中标注的,但是芯片手册中并未指出,暂时不知道具体原因。

下面介绍几个常用的API函数:

  1. 引脚初始化:void gpio_init (gpio_pin_enum pin, gpio_dir_enum dir, uint8 dat, gpio_mode_enum pinmode)
  2. 设置引脚输出电平:void gpio_set_level (gpio_pin_enum pin, uint8 dat)
  3. 获取引脚输入电平:uint8 gpio_get_level (gpio_pin_enum pin)
  4. 翻转引脚电平:void gpio_toggle_level (gpio_pin_enum pin)

在初始化引脚的函数中,对引脚电平的设置只在引脚设置为输出模式(GPO)下才有用

pinmode主要有:

typedef enum
{
    GPI_FLOATING_IN,       // 定义管脚浮空输入
    GPI_PULL_UP    ,       // 定义管脚上拉输入
    GPI_PULL_DOWN  ,       // 定义管脚下拉输入

    GPO_PUSH_PULL  ,       // 定义管脚推挽输出
    GPO_OPEN_DTAIN ,       // 定义管脚开漏输出
}gpio_mode_enum;

具体可以参考这篇文章:【STM32】STM32F4 GPIO八种模式及工作原理详解

PIT产生简单的定时中断

常用API函数有:

  1. 初始化PIT定时器:void pit_init (pit_index_enum pit_index, uint32 time)
  2. 对pit_init的封装,方便设置ms级定时器中断:pit_ms_init(pit_index, time)
  3. 对pit_init的封装,方便设置us级定时器中断:pit_us_init(pit_index, time)

Infineon单片机中并没有PIT外设,这些函数是对官方库中CCU6模块的封装

在初始化函数中由这句restoreInterrupts(interrupt_state);开启中断

由这句IfxCcu6_Timer_start(&g_Ccu6Timer);开启定时器

所以我们不需要自己手动开启,但是要关闭的话得手动关闭

void pit_close               (pit_index_enum pit_index);
void pit_start               (pit_index_enum pit_index);
void pit_all_close           (void);
void pit_disable             (pit_index_enum pit_index);
void pit_enable              (pit_index_enum pit_index);

如果是简单的延时可以调用systick函数 

中断函数入口和优先级

逐飞的工程目录如下:

  

其中code文件夹是我们存放自己编写的.c、.h文件,libraries是库文件,不需要改动,user文件夹下isr.c中是所有的中断处理函数入口,可以直接类比到STM32的IRQHandler函数 

 并且逐飞已经添加了去除中断标志的函数,我们使用时可以直接把这部分复制到main.c中然后进行后续开发。

 isr_config.h文件下是所有中断的优先级定义和决定中断由谁处理

TC264是双核的芯片,但是如何在不出错的情况下合理使用两个CPU笔者还未研究,目前只使用CPU0

特别注意:所有中断优先级都必须设置为不一样的值,TC264具有255个中断优先级可以设置

1-255,0优先级表示不开启中断,255为最高优先级


 下面举一个利用状态机进行按键检测的例子,主要涉及GPIO的基础API、PIT的20ms定时中断。这样完成的按键检测,既实现了消抖,也不会让CPU空等。如果利用外部中断进行按键检测,如果按键长按,可能多次进入中断,或者必须在中断函数中等待按键松开。

typedef enum
{
    KEY_CHECK = 0,  //按键检测状态
    KEY_COMFIRM,    //按键确认状态
    KEY_UNPRESSED     //按键释放状态
}keyState_e;        //状态枚举变量

typedef struct
{
  keyState_e keyState; //按键状态
  uint8 keyFlag;     //按键按下标志
}key_t;                //按键状态结构体

key_t Key[4];

void KeyCheck(int i, key_t *Key, gpio_pin_enum pin)
{
    switch( Key[i].keyState )
    {
        case KEY_CHECK:
            // 读到低电平,进入按键确认状态
            if(gpio_get_level(pin) == GPIO_LOW)
            {
                Key[i].keyState = KEY_COMFIRM;
            }
        break;

        case KEY_COMFIRM:
            if(gpio_get_level(pin) == GPIO_LOW)
            {
                //读到低电平,按键确实按下,按键标志位置1,并进入按键释放状态
                Key[i].keyState = KEY_UNPRESSED;
                Key[i].keyFlag = 1;
            }
            //读到高电平,可能是干扰信号,返回初始状态
            else
            {
                Key[i].keyState = KEY_CHECK;
            }
        break;

        case KEY_UNPRESSED:
            if(gpio_get_level(pin) == GPIO_HIGH)
            {
             // 读到高电平,说明按键释放,返回初始状态
             Key[i].keyState = KEY_CHECK;
            }
        break;

        default: break;
    }
}


int core0_main(void)
{
    //定义变量
    uint8 i;

    clock_init();                   // 获取时钟频率<务必保留>
    debug_init();                   // 初始化默认调试串口
    // 此处编写用户代码 例如外设初始化代码等

    //由于逐飞的母版上按键电路有电阻上拉到高电平,所有GPIO设置为浮空输入即可
    gpio_init(BUTTON1, GPI, GPIO_LOW, GPI_FLOATING_IN);
    gpio_init(BUTTON2, GPI, GPIO_LOW, GPI_FLOATING_IN);
    gpio_init(BUTTON3, GPI, GPIO_LOW, GPI_FLOATING_IN);
    gpio_init(BUTTON4, GPI, GPIO_LOW, GPI_FLOATING_IN);

    pit_ms_init(PIT_NUM, 20);          // 初始化 CCU6_0_CH0 为周期中断

    // 此处编写用户代码 例如外设初始化代码等
    cpu_wait_event_ready();         // 等待所有核心初始化完毕

	while (TRUE)
	{
        // 此处编写需要循环执行的代码

        if(pit_state)
        {
            KeyCheck(0,Key,BUTTON1);
            KeyCheck(1,Key,BUTTON2);
            KeyCheck(2,Key,BUTTON3);
            KeyCheck(3,Key,BUTTON4);
            pit_state = 0;           // 清空周期中断触发标志位
        }

        for(i = 0;i<4;i++)
        {
            if(Key[i].keyFlag == 1)
            {
                printf("button %d pressed!\n",i);
                Key[i].keyFlag = 0; //清除按键按下标志
            }
        }
	}
}

IFX_INTERRUPT(cc60_pit_ch0_isr, 0, CCU6_0_CH0_ISR_PRIORITY)
{
    interrupt_global_enable(0);                     // 开启中断嵌套
    pit_clear_flag(CCU60_CH0);

    pit_state = 1;
}

串口的收发——接收数据并解析(上位机调试)

在debug_init函数中逐飞已经完成了默认串口的初始化,默认的串口是

 串口发送数据很简单,逐飞库已经完成了printf函数的重定向,可以直接调用printf函数

或者使用如下函数:

void    uart_write_byte_wait                (uart_index_enum uart_n, const uint8 dat);
void    uart_write_byte                     (uart_index_enum uartn, const uint8 dat);
void    uart_write_buffer                   (uart_index_enum uartn, const uint8 *buff, uint32 len);
void    uart_write_string                   (uart_index_enum uartn, const char *str);

接收数据是比较难且重要的一部分,因为使用上位机调试或者蓝牙和wifi等都需要串口能正确接收我们发送的数据并解析

本文仅讨论接收定长数据并解析,因为我们调试的过程中一般会按固定的格式发送

主要思路为:开启串口接收中断,把读到的数据先存入fifo,当读到指定数目后进入checkCmd函数检查格式,如果格式正确就进入usart_analysis

注意处理完毕要及时清空接受数组在进行下一次接收

如果有更好的思路欢迎分享

#define UART_INDEX              (DEBUG_UART_INDEX   )                           // 默认 UART_0
#define UART_BAUDRATE           (DEBUG_UART_BAUDRATE)                           // 默认 115200
#define UART_TX_PIN             (DEBUG_UART_TX_PIN  )                           // 默认 UART0_TX_P14_0
#define UART_RX_PIN             (DEBUG_UART_RX_PIN  )                           // 默认 UART0_RX_P14_1

#define LED1                    P20_9

uint8 uart_get_data[64];                                                        // 串口接收数据缓冲区
uint8 fifo_get_data[64];                                                        // fifo 输出读出缓冲区

uint8  get_data = 0;                                                            // 接收数据变量
uint32 fifo_data_count = 0;                                                     // fifo 数据个数

fifo_struct uart_data_fifo;

int core0_main(void)
{
    clock_init();                   // 获取时钟频率<务必保留>
    debug_init();                   // 初始化默认调试串口
    // 此处编写用户代码 例如外设初始化代码等

    fifo_init(&uart_data_fifo, FIFO_DATA_8BIT, uart_get_data, 64);              // 初始化 fifo 挂载缓冲区
    gpio_init(LED1, GPO, GPIO_HIGH, GPO_OPEN_DTAIN);
    uart_rx_interrupt(UART_INDEX, 1);                                           // 开启 UART_INDEX 的接收中断

    cpu_wait_event_ready();         // 等待所有核心初始化完毕
	while (TRUE)
	{
        // 此处编写需要循环执行的代码


	}
}


_Bool checkCmd(uint8_t* str)
{
    //仅作举例  CNBR:A392:200202120000 蓝桥杯误入
    if((str[0] == 'C' || str[0] == 'V') && str[1] == 'N' && str[2] == 'B' && str[3] == 'R' && str[4] == ':' && str[9] == ':')
    {
        uint8_t i;
        for(i = 10; i < 22; i++)
        {
            if(str[i] > '9' || str[i] < '0')
                return 0;
        }
        return 1;
    }
    else
    {
        memset(fifo_get_data,0,22);
        return 0;
    }
}


//-------------------------------------------------------------------------------------------------------------------
// 函数简介       UART_INDEX 的接收中断处理函数 这个函数将在 UART_INDEX 对应的中断调用
// 参数说明       void
// 返回参数       void
// 使用示例       uart_rx_interrupt_handler();
//-------------------------------------------------------------------------------------------------------------------
void uart_rx_interrupt_handler (void)
{
//    get_data = uart_read_byte(UART_INDEX);                                      // 接收数据 while 等待式 不建议在中断使用
    uart_query_byte(UART_INDEX, &get_data);                                     // 接收数据 查询式 有数据会返回 TRUE 没有数据会返回 FALSE
    fifo_write_buffer(&uart_data_fifo, &get_data, 1);                           // 将数据写入 fifo 中
    fifo_data_count = fifo_used(&uart_data_fifo);                           // 查询数组当前数据个数
    if(fifo_data_count == 22)                                                //读到指定数目后开始解析
    {
        fifo_read_buffer(&uart_data_fifo, fifo_get_data, &fifo_data_count, FIFO_READ_AND_CLEAN);  // 将 fifo 中数据读出并清空 fifo 挂载的缓冲
        //一些格式判断语句,防止有数据丢失导致格式错误
        if(checkCmd(fifo_get_data))
        {
            gpio_toggle_level(LED1);
            //usart_analysis(); 串口解析函数,需要自己编写
            memset(fifo_get_data,0,fifo_data_count);
        }
    }
}


IFX_INTERRUPT(uart0_rx_isr, 0, UART0_RX_INT_PRIO)
{
    interrupt_global_enable(0);                     // 开启中断嵌套
    IfxAsclin_Asc_isrReceive(&uart0_handle);

    uart_rx_interrupt_handler();                    // 串口接收处理
}

PWM的产生——以呼吸灯为例

常用API函数有: 

  1. PWM初始化:void pwm_init (pwm_channel_enum pwmch, uint32 freq, uint32 duty)
  2. 设置占空比:void pwm_set_duty (pwm_channel_enum pwmch, uint32 duty)

在初始化函数中已经由IfxGtm_Atom_Pwm_start(&g_atomDriver, TRUE);打开了PWM,不需要手动开启

可产生PWM的引脚不是任意的,只能选用逐飞定义的枚举变量

最大占空比PWM_DUTY_MAX默认为10000,可在头文件中自行修改

for(duty = 0; duty <= PWM_DUTY_MAX / 2; duty ++)                        // 输出占空比递增到 50%
{
    // 呼吸流水灯
    for(channel_index = 0; channel_index < CHANNEL_NUMBER; channel_index++) 
    {
        duty_temp = (duty + channel_index * PWM_DUTY_MAX / 8) % (PWM_DUTY_MAX / 2) + (PWM_DUTY_MAX / 2); 
        pwm_set_duty(channel_list[channel_index], duty_temp);           // 更新对应通道占空比
    }
    system_delay_us(200);
}

每隔一段时间改变一次PWM的占空比,就可以形成呼吸灯的效果


笔者水平有限,本文仅作总结与分享,欢迎批评指正,手动笔芯~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/406265.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

阿里P8大牛用实例跟你讲明白“Java 微服务架构实战”

全文一共十五章&#xff0c;核心内容为SpringBoot、SpringCloud、Docker、RabbitMQ消息组件。其中&#xff0c;SpringBoot是SpringMVC 技术的延伸&#xff0c;使用它进行程序开发会更简单&#xff0c;服务整合也会更容易。SpringCloud 是当前微架构的核心技术方案&#xff0c;属…

Spring Cloud Alibaba 微服务1,系统架构演变 + Nginx反向代理与负载均衡

目录专栏导读一、系统架构演变二、什么是Nginx&#xff1f;三、servername匹配规则四、正向代理与反向代理1、正向代理2、反向代理3、LVS五、负载均衡策略1、轮询2、权重3、ip_hash4、least_conn5、url_hash6、fair7、小结六、动静分离七、URLRewrite专栏导读 &#x1f3c6;作者…

【Linux系统】进程概念

目录 1 冯诺依曼体系结构 2 操作系统(Operator System) 概念 设计OS的目的 定位 总结 系统调用和库函数概念 3 进程 3.1 基本概念 3.2 描述进程-PCB 3.2 组织进程 3.3 查看进程 3.4 通过系统调用获取进程标示符 3.5 进程状态 在了解进程概念前我们还得了解下冯诺…

MongoDB详解,用心看这篇就够了【重点】

1.1 MongoDB概述 MongoDB是一个基于分布式文件存储的数据库。由C语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。 MongoDB是一个介于关系数据库和非关系数据库之间的产品&#xff0c;是非关系数据库当中功能最丰富&#xff0c;最像关系数据库的。 它支持的数据…

业内人士真心话,软件测试是没有前途的,我慌了......

我在测试行业爬模滚打7年&#xff0c;从点点点的功能测试到现在成为高级测试&#xff0c;工资也翻了几倍。个人觉得&#xff0c;测试的前景并不差&#xff0c;只要自己肯努力。 我刚出来的时候是在鹅厂做外包的功能测试&#xff0c;天天点点点&#xff0c;很悠闲&#xff0c;点…

JS中的构造函数

构造函数 1.构造函数 创建一个构造函数&#xff0c;专门用来创建一个指定的对象的构造函数就是普通的函数&#xff0c;创建方式和普通函数没有区别&#xff0c;不同的是构造函数习惯上首字母大写构造函数和普通函数的区别就是调用方式不同 普通函数是直接调用的&#xff0c;而…

真题解析 | 2022数模美赛C题:股票投资策略

1、准备工作 1.1 题目背景 市场交易者频繁买卖波动性资产&#xff0c;目标是最大化其总回报。每次买卖通常都会有佣金。 两种这样的资产是黄金和比特币。 图 1&#xff1a;黄金每日价格&#xff0c;每金衡盎司美元。 资料来源&#xff1a;伦敦金银市场协会&#xff0c;2021 年…

javaScript实现动态规划(Dynamic Programming)01背包问题

&#x1f431; 个人主页&#xff1a;不叫猫先生 &#x1f64b;‍♂️ 作者简介&#xff1a;前端领域新星创作者、阿里云专家博主&#xff0c;专注于前端各领域技术&#xff0c;共同学习共同进步&#xff0c;一起加油呀&#xff01; &#x1f4ab;系列专栏&#xff1a;vue3从入门…

二十分钟带你了解JVM性能调优与实战进阶

ZGC 诞生原因 Java生态非常强大&#xff0c;但还不够&#xff0c;有些场景仍处于劣势&#xff0c;而ZGC的出现可以让Java语言抢占其他语言的某些特定领域市场。比如 谷歌主导的Android手机系统显示卡顿。证券交易市场&#xff0c;实时性要求非常高&#xff0c;目前主要是C主…

Day16【元宇宙的实践构想04】—— 元宇宙的安全

&#x1f483;&#x1f3fc; 本人简介&#xff1a;男 &#x1f476;&#x1f3fc; 年龄&#xff1a;18 ✍今日内容&#xff1a;《元宇宙的实践构想》04——元宇宙的安全 ❗❗❗从1.31日开始&#xff0c;阿亮每天会查阅一些元宇宙方面的小知识&#xff0c;和大家一起分享。一是由…

ChatGPT背后的技术和多模态异构数据处理的未来展望——我与一位资深工程师的走心探讨

上周&#xff0c;我和一位从业三十余年的工程师聊到ChatGPT。 作为一名人工智能领域研究者&#xff0c;我也一直对对话式大型语言模型非常感兴趣&#xff0c;在讨论中&#xff0c;我向他解释这个技术时&#xff0c;他瞬间被其中惊人之处所吸引&#x1f64c;&#xff0c;我们深…

读书笔记——《再见,平庸时代》

为什么会看这本书 《马斯克》这本书中&#xff0c;最后几段介绍了一下经济学家和作者泰勒考恩的两本书《大停滞》《再见&#xff0c;平庸时代》。《大停滞》讲的是美国这40年发展为何停滞&#xff0c;我当然不太关心这种内容。但是《再见&#xff0c;平庸时代》不是对历史的研究…

springboot 东方通(tongweb)替换tomcat

一.修改pom.xml文件依赖 1.排除springboot中内置的tomcat依赖 2.添加tongweb-spring-boot-starter和tongweb-embed依赖 特别说明下&#xff1a;我这里所有依赖的包都传到了私有仓库&#xff0c;直接复制到pom.xml文件会import失败。 <!-- SpringBoot Web容器 --> <d…

分享Python7个爬虫小案例(附源码)

本次的7个python爬虫小案例涉及到了re正则、xpath、beautiful soup、selenium等知识点&#xff0c;非常适合刚入门python爬虫的小伙伴参考学习。注&#xff1a;若涉及到版权或隐私问题&#xff0c;请及时联系我删除即可。 1.使用正则表达式和文件操作爬取并保存“某吧”某帖子…

【uniapp小程序实战】—— 使用腾讯地图获取定位

文章目录&#x1f34d;前言&#x1f34b;正文1、首先看官网uni.getLocation(OBJECT)#注意2、腾讯位置服务平台申请密钥和下载SDK2.1 申请开发者秘钥2.2 开通webserviceAPI服务2.3 下载微信小程序JavaScriptSDK2.4 安全域名设置3、配置manifest.json文件4、示例代码展示4.1 引用…

如何用Python求解微分方程组

文章目录odeint简介示例odeint简介 scipy文档中将odeint函数和ode, comples_ode这两个类称为旧API&#xff0c;是scipy早期使用的微分方程求解器&#xff0c;但由于是Fortran实现的&#xff0c;尽管使用起来并不方便&#xff0c;但速度没得说&#xff0c;所以有的时候还挺推荐…

JavaScript基础(详细总结)

目录 1、JavaScript简介 1.2、JavaScript的发展史 1.3、JavaScript的功能 1.4、JavaScript的特点 1.5、JavaScript组成 2、JavaScript基础语法 2.1、HTML引入JS 2.1.1、内部引入 2.1.2、外部引入 2.2、JS输出数据的三种方式 2.2.1、浏览器弹窗 2.2.2、输出HTML页面…

IDEA实现前端页面登录,注册、增、删、改、查操作-完整版

分层思想&#xff1a;entity层&#xff1a;存放实体类vo层&#xff1a;消息模型&#xff08;重复使用的一些属性&#xff09;mapper层&#xff1a;接口&#xff08;写方法的&#xff09;mapper.xml:MyBatis与数据库相关的一些内容controller(web)层&#xff1a;接收前端传回的参…

谈谈ES5和ES6的区别

我们都知道JavaScript是由三部分组成&#xff1a; 1. ECMAScript(核心)&#xff1a;规定了语言的组成部分>语法、类型、语句、关键字、保留字、操作符、对象 2. BOM(浏览器对象模型): 支持访问和操作浏览器窗口&#xff0c;可以控制浏览器显示页面以外的部分。 3. DOM(文…

基于Python构建机器学习Web应用

目录 一、内容介绍 1.Onnx模型 ①skl2onnx库安装 2.Netron安装 二、模型构建 1.数据加载 2.划分可训练特征与预测标签 3.训练模型 ①第三方库导入 ②数据集划分 ③SVC模型构建 ④精度评价 二、模型转换及可视化 1.参数配置 2.Onnx模型生成 3.可视化模型 四、构…