本帖最后由 h1654155283.0188 于 2022-12-2 13:20 编辑
第三章 LED流水灯多样展示
本章节主要体验的是
时钟配置、GPIO的输出功能,及
通用定时器的基本基本定时功能,用阻塞式及非阻塞式两种方式实现流水灯。
一、了解一下FSP
FSP 全称为“Flexible Software Package”,中文译为“灵活配置软件包”,FSP 旨在以较低的内存占用量提供快速高效的驱动程序和协议栈,FSP 集成了中间件协议栈、独立于RTOS 的硬件抽象层(HAL)驱动程序,以及最基础的板级支持包(BSP)驱动程序,有层次划分分明的软件结构。
二、时钟配置
系统中的每一个外围设备都需要不同的工作频率,因此需要配置不同的时钟频率,来满足不同模块的需求,
开发板是有24Mhz的外部高速时钟的,所以我们选择时钟来源Main Clock Oscillator (MOSC),这个开发板最大的时钟是100MHz,经验设置96MHz比较好。
这里有几个注意事项:
要注意各个环节的输出频率,例如PLL的输出为100MHz~200MHz;
时钟频率设置限制: ICLK ≥ PCLKA ≥ PCLKB, PCLKD ≥ PCLKA ≥ PCLKB,ICLK ≥ FCLK
三、GPIO输出体验
1、了解硬件设计
RA-Eco-RA4M2开发板LED
威廉希尔官方网站
图如图所示,图中RA4M2 芯片的P4015、P404、P405 引脚分别连接到LED1、LED2、LED3 这三个LED 灯后通过一个4.7 KΩ 的限流电阻连接地,只要开发板对应IO口高电平就会亮。
2、软件工程设计
在上一章建立的工程的基础上,打开FSP配置界面。在FSP 配置界面里面点开“Pins”-> “Ports”-> “P4”-> “P415”,然后将连接到LED 灯的IO引脚的“Mode”属性配置为“Output mode (Ini
tial Low)”,表示该引脚默认输出低电平,其他的属性默认即可,其他的LED 引脚“P404”、“P405”也是按照这样子配置,其实通过上一章的建立工程,这些配置已经基本完成了,然后进行第六步生成代码。可以通过按下快捷键“Ctrl + S”保存。
Pin Configuration 页面的IOPORT 属性介绍:
IOPORT 属性
| 描述
|
Mode
| IO 引脚的工作模式,包括输入模式和输出模式(可配置为默认输出高/低电平)。
|
Pull up
| IO 引脚是否上拉。
|
Drive Capacity
| IO 引脚的驱动能力。
|
Output type
| IO 引脚的输出类型。可以选CMOS 推挽输出或开漏输出。
|
3、工程函数编写
可以看到,工程目录下的“pin_data.c”源文件,就会看到g_bsp_pin_cfg_data 数组中已经加入了LED 引脚的配置数据。创建的工程是没有使用RTOS 的,所以C 语言程序的入口函数main 函数调用了hal_entry 函数,用户程序从hal_entry 函数开始执行,也是在hal_entry 函数里面编写我们的代码。
实现LED 灯的循环点亮,其思路非常地简单:首先初始化配置LED 引脚,LED1-LED2-LED3如此反复循环,间隔1s,这里主要用到的函数在“bsp_io.h”中,通过“R_BSP_PinWrite (bsp_io_port_pin_t pin, bsp_io_level_t level)”写引脚状态,软件延时函数使用“R_BSP_SoftwareDelay (uint32_t delay, bsp_delay_units_t units)”,在“bsp_delay.c”中。
- ///************************************宏定义************************************/
- #define LED1_on R_BSP_PinWrite (BSP_IO_PORT_04_PIN_15, BSP_IO_LEVEL_HIGH)
- #define LED1_off R_BSP_PinWrite (BSP_IO_PORT_04_PIN_15, BSP_IO_LEVEL_LOW)
- #define LED2_on R_BSP_PinWrite (BSP_IO_PORT_04_PIN_04, BSP_IO_LEVEL_HIGH)
- #define LED2_off R_BSP_PinWrite (BSP_IO_PORT_04_PIN_04, BSP_IO_LEVEL_LOW)
- #define LED3_on R_BSP_PinWrite (BSP_IO_PORT_04_PIN_05, BSP_IO_LEVEL_HIGH)
- #define LED3_off R_BSP_PinWrite (BSP_IO_PORT_04_PIN_05, BSP_IO_LEVEL_LOW)
- /***********************************变量声明***********************************/
- /***********************************函数声明***********************************/
- void LED_init(void);
- void App_LED(void);
- //******************************************************************************
- // 函数名称 : LED_init
- // 函数描述 : LED初始状态设定
- // 输入参数 :
- // 参数描述 : 无
- // 输出参数 : 无
- // 返回值 : 无
- //******************************************************************************
- void LED_init(void)
- {
- LED1_off;
- LED2_off;
- LED3_off;
- }
- //******************************************************************************
- // 函数名称 : App_LED
- // 函数描述 : LED操作显示,目前为循环显示
- // 输入参数 :
- // 参数描述 : 无
- // 输出参数 : 无
- // 返回值 : 无
- //******************************************************************************
- void App_LED(void)
- {
- R_BSP_PinAccessEnable();
- LED_init();
- LED1_on;
- R_BSP_SoftwareDelay (1, BSP_DELAY_UNITS_SECONDS);
- LED1_off;
- LED2_on;
- R_BSP_SoftwareDelay (1, BSP_DELAY_UNITS_SECONDS);
- LED2_off;
- LED3_on;
- R_BSP_SoftwareDelay (1, BSP_DELAY_UNITS_SECONDS);
- R_BSP_PinAccessDisable();
- }
这里需要注意一下R_BSP_PinAccessEnable();在进行IO口操作一定要启用对PFS寄存器的访问,已经实验不开启对IO口的操作是失败的。
将程序编译并下载到开发板之后,可以观察到开发板上面3 个LED 灯间隔1s依次循环点亮。
四、定时器的定时功能
本步骤主要是通过定时器的定时功能实现非阻塞式LED流水灯。
在FSP 配置界面里面点开“Stacks→New Stack→Timers→Timer”,如下图:
定时器的配置如下:
定时机器配置这里,我们首先了解一下,本次是想实现非阻塞式的定时功能,就是一个基本定时功能,为了后边也可以使用这个定时,初步设定为10ms基本定时,频率=1s/10ms=系统时钟/period,可以得出period=960000.
其实定时器的配置有多种方式,可以直接选择其他单位,例如计数单位为Milliseconds,period可以直接配置对应的10.
通常意义上的中断就是这里面的Callback(回调函数),发生中断后就会执行timer0_Callback函数中的内容,这里需要注意一下,一定要设置中断优先级(Priority),未设置的话FSP会显示红色。之后“Ctrl + S”保存再加上“Generate”。
这里需要注意一下,生成的代码指示初始化部分,需要写入启动和回调函数,才能真正的开启定时器功能。
- typedef struct
- {
- uint8_t Mode_Dis; //LED显示模式
- uint8_t Mode_OidDis; //LED上一次显示模式
- uint8_t PWMcnt; //LED控制模式
- uint8_t state; //LED过程
- uint8_t UpFlag; //更新标志
- uint8_t Upcnt; //更新计时计数
- }LED_states;
- LED_states LED;
- //******************************************************************************
- // 函数名称 : App_LED
- // 函数描述 : LED模式操作
- // 输入参数 :
- // 参数描述 : 无
- // 输出参数 : 无
- // 返回值 : 无
- //******************************************************************************
- void App_LED(void)
- {
- // const bsp_delay_units_t bsp_delay_units = BSP_DELAY_UNITS_MILLISECONDS;
- // const uint32_t freq_in_hz = 2;
- // const uint32_t delay = bsp_delay_units / freq_in_hz;
-
- if(LED.UpFlag == 1)
- {
- R_BSP_PinAccessEnable();
- LED_init();
- switch(LED.state)
- {
- case 0:
- LED1_on;
- break;
- case 1:
- LED2_on;
- break;
- case 2:
- LED3_on;
- break;
- default:
- break;
- }
- R_BSP_PinAccessDisable();
- LED.UpFlag = 0;
- }
-
- }
在这里创建一个结构体用于LED相关状态的指示,同时修改LED的流水灯程序(经过功能的增加,这块还会变动)。
- void timer0_callback(timer_callback_args_t *p_args)
- {
- /* TODO: add your own code here */
- if (TIMER_EVENT_CYCLE_END == p_args->event)
- {
- if(LED.UpFlag == 0)
- {
- LED.Upcnt++;
- if(LED.Upcnt%100 == 0)
- {
- LED.state++;
- LED.state %= 3;
- LED.Upcnt = 0;
- LED.UpFlag = 1;
- }
- }
- }
- }
- //******************************************************************************
- //* 函数名称 : Tmr0_GPT_init
- //* 函数描述 : 开启定时器
- //* 输入参数 :
- //* 参数描述 :
- //* 输出参数 : 无
- //* 返回值 : 无
- //******************************************************************************
- void Tmr0_GPT_init(void)
- {
- fsp_err_t err = FSP_SUCCESS;
- /* Initializes the module. */
- err = R_GPT_Open(&g_timer0_ctrl, &g_timer0_cfg);
- /* Handle any errors. This function should be defined by the user. */
- assert(FSP_SUCCESS == err);
- /* Start the timer. */
- (void) R_GPT_Start(&g_timer0_ctrl);
- }
注意在 "hal_data.h"虽然定义了设置的回调函数,但是还是需要在 "hal_entry.c"中重新定义timer0_callback(timer_callback_args_t *p_args),生成的代码中并没有能直接编码的地方。
效果和阻塞式流水灯一样。
总结:
FSP的可视化代码工具还是很方便的,不过网上的教程还是不多的,有一些方面还是需要多加注意,例如定时器的回调并没有直接生成,只是定义了一个,I/O的写操作之前还需要启用对PFS寄存器的访问,等等。这些小方面如果没有对应的教程很容易忽略,所以还是希望官方能多出一点系统的教程。
本人使用的IAR搭配FSP进行的编程,对于自己新建的文件需要通过FSP“Generate”后才能自动获取,自行添加是不成功的。
在IAR中,“Program Entry”下添加文件夹也是失败,可以见的FSP对生成工程的结构控制非常严格,灵活度不够。