1. 前言
终于准备开发瑞萨的板子了,开始按照教程一步一步的搭建环境,还是非常不容易的。
本次开发使用的是瑞萨官方的编译器RASC+Keil。
本文实现的功能:
- 从头创建一个新工程;
- 配置LED以及按键端口;
- 使用Renesas Flash Programmer下载程序;
- 实现流水灯以及按键SW1按下停止流水灯,按键SW2按下开启流水灯的功能。
2. 配置工程
打开RASC,可直接跳过登录账号,也可登录在瑞萨官网注册的账号即可,然后按照下面的步骤新建工程即可。
2.1 新建FSP项目
输入项目名称LED_switch
选择目标单片机
所使用的单片机为R7FA4M2AD3DFP,如果有调试器,可以选择相应的调试器,否则可以选择None,当然后期可以修改。
选择工程类型
这里直接选择Flat Project就行,如果需要体验TrustZone,,可根据实际情况选择。
选择编译方式
这里选择第一个即可。
选择是否使用FreeRTOS
我这里选择了使用,方便后期开发,但是只能选择使用静态分配的任务。
然后点击完成。
到这里工程就算新建完成,但是什么都没有,需要我们通过FSP添加想要的组件,完成功能开发。
2.2 硬件连接以及FSP配置
2.2.1 硬件连接
我们需要用到LED以及按键,先查看原理图。
LED原理图如下,由此可知,P405,P404,P002分别控制LED1,LED2,LED3,并且当控制引脚为HIGH的时候LED亮。
按键原理图如下,由此可知,P005连接到了SW01,P006连接到了SW2,且当引脚为LOW时表示按键按下。
2.2.2 FSP配置
知道了硬件连接,接下来就是使用FSP配置响应的硬件功能了。
配置按键P005,P006为输入模式。
选择FSP Configuration下面的Pins,配置引脚P405,P404,P002,配置为输出低[Output mode(Initial Low)]。
点击Generate Project Content生成配置代码。
选择Summary,进入项目文件夹
3. 软件实现
3.1 实现的功能
- 系统上电,LED1,LED2,LED3按照亮灭,亮灭,亮灭的状态流水灯显示,流水灯切换周期为500ms;
- 按下按键SW1,流水灯停止;
- 按下按键SW2,流水灯继续;
3.2 FreeRTOS使用
创建工程的时候选择了使用FreeRTOS,RASC会默认配置一个最小配置项的freeRTOS环境,只支持基本的功能,很多扩展功能都不支持,只支持静态创建任务,我还没找到在哪里可以配置,因为直接修改配置文件不行,RASC再次生成的时候会覆盖。
虽然freeRTOS只支持静态配置以及一些基础功能,但是也够我们使用了,下面开始实现我的逻辑。
3.2.1 Stack分配函数
实现Idle任务的Stack分配函数,因为是静态分配栈,所以该部分功能需要我们自己实现,FreeRTOS提供了接口。
void vApplicationGetIdleTaskMemory(StaticTask_t ** ppxIdleTaskTCBBuffer,
StackType_t ** ppxIdleTaskStackBuffer,
uint32_t * pulIdleTaskStackSize)
{
*ppxIdleTaskTCBBuffer = &xIdleTaskTcb;
*ppxIdleTaskStackBuffer = xIdleTaskStack;
*pulIdleTaskStackSize = 1024;
}
实现Timer任务的Stack分配函数
因为是静态分配栈,所以该部分功能需要我们自己实现,FreeRTOS提供了接口。
void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer,
StackType_t **ppxTimerTaskStackBuffer,
uint32_t *pulTimerTaskStackSize)
{
*ppxTimerTaskTCBBuffer = &xTimerTaskTcb;
*ppxTimerTaskStackBuffer = xTiemrTaskStack;
*pulTimerTaskStackSize = 2048;
}
3.2.2 LED任务
LED任务实现流水灯功能,每200ms切换一次。
任务创建:
Task_Led_Handle = xTaskCreateStatic(Task_LedRunning,
"Led",
1024,
NULL,
4,
xTaskLedStack,
&xTaskLedTcb);
LED任务实现:
static void Task_LedRunning(void *pvParameters)
{
(void)pvParameters;
for (;;)
{
R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_04_PIN_04, BSP_IO_LEVEL_HIGH);
R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_04_PIN_05, BSP_IO_LEVEL_LOW);
R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_04_PIN_15, BSP_IO_LEVEL_LOW);
vTaskDelay(pdMS_TO_TICKS(200));
R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_04_PIN_04, BSP_IO_LEVEL_LOW);
R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_04_PIN_05, BSP_IO_LEVEL_HIGH);
R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_04_PIN_15, BSP_IO_LEVEL_LOW);
vTaskDelay(pdMS_TO_TICKS(200));
R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_04_PIN_04, BSP_IO_LEVEL_LOW);
R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_04_PIN_05, BSP_IO_LEVEL_LOW);
R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_04_PIN_15, BSP_IO_LEVEL_HIGH);
vTaskDelay(pdMS_TO_TICKS(200));
}
}
3.2.3 Key任务
按键实现了对按键SW1与SW2的采集,滤波等功能,任务周期为10ms,滤波时间为40ms。
当SW1按下,暂停LED任务;
当SW2按下,恢复LED任务。
任务创建:
Task_Key_Handle = xTaskCreateStatic(Task_KeyRunning,
"Key",
1024,
NULL,
3,
xTaskKeyStack,
&xTaskKeyTcb);
任务实现:
static void Task_KeyRunning(void *pvParameters)
{
(void)pvParameters;
bsp_io_level_t key_Status[2] = {BSP_IO_LEVEL_HIGH, BSP_IO_LEVEL_HIGH};
uint16_t key_press_cnt[2] = {0U, 0U};
for (;;)
{
if (FSP_SUCCESS == R_IOPORT_PinRead(&g_ioport_ctrl, BSP_IO_PORT_00_PIN_05, &key_Status[0]))
{
if (key_Status[0] == BSP_IO_LEVEL_LOW)
{
if (key_press_cnt[0] >= 0U)
{
vTaskSuspend(Task_Led_Handle);
}
else
{
key_press_cnt[0] ++;
}
}
else
{
key_press_cnt[0] = 0U;
}
}
if (FSP_SUCCESS == R_IOPORT_PinRead(&g_ioport_ctrl, BSP_IO_PORT_00_PIN_06, &key_Status[1]))
{
if (key_Status[1] == BSP_IO_LEVEL_LOW)
{
if (key_press_cnt[1] >= 4U)
{
vTaskResume(Task_Led_Handle);
}
else
{
key_press_cnt[1] ++;
}
}
else
{
key_press_cnt[1] = 0U;
}
}
vTaskDelay(pdMS_TO_TICKS(10));
}
}
3.3 程序设计
hal_entry.c
完整代码
#include "hal_data.h"
#include "FreeRTOS.h"
#include "task.h"
FSP_CPP_HEADER
void R_BSP_WarmStart(bsp_warm_start_event_t event);
FSP_CPP_FOOTER
static StackType_t xIdleTaskStack[512];
static StaticTask_t xIdleTaskTcb;
static StackType_t xTiemrTaskStack[512];
static StaticTask_t xTimerTaskTcb;
static StackType_t xTaskLedStack[1024];
static StaticTask_t xTaskLedTcb;
static TaskHandle_t Task_Led_Handle = NULL;
static StackType_t xTaskKeyStack[1024];
static StaticTask_t xTaskKeyTcb;
static TaskHandle_t Task_Key_Handle = NULL;
extern void vApplicationGetIdleTaskMemory(StaticTask_t ** ppxIdleTaskTCBBuffer,
StackType_t ** ppxIdleTaskStackBuffer,
uint32_t * pulIdleTaskStackSize);
extern void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer,
StackType_t **ppxTimerTaskStackBuffer,
uint32_t *pulTimerTaskStackSize);
static void Task_LedRunning(void *pvParameters);
static void Task_KeyRunning(void *pvParameters);
static void Task_LedRunning(void *pvParameters)
{
(void)pvParameters;
for (;;)
{
R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_04_PIN_04, BSP_IO_LEVEL_HIGH);
R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_04_PIN_05, BSP_IO_LEVEL_LOW);
R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_00_PIN_02, BSP_IO_LEVEL_LOW);
vTaskDelay(pdMS_TO_TICKS(200));
R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_04_PIN_04, BSP_IO_LEVEL_LOW);
R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_04_PIN_05, BSP_IO_LEVEL_HIGH);
R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_00_PIN_02, BSP_IO_LEVEL_LOW);
vTaskDelay(pdMS_TO_TICKS(200));
R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_04_PIN_04, BSP_IO_LEVEL_LOW);
R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_04_PIN_05, BSP_IO_LEVEL_LOW);
R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_00_PIN_02, BSP_IO_LEVEL_HIGH);
vTaskDelay(pdMS_TO_TICKS(200));
}
}
static void Task_KeyRunning(void *pvParameters)
{
(void)pvParameters;
bsp_io_level_t key_Status[2] = {BSP_IO_LEVEL_HIGH, BSP_IO_LEVEL_HIGH};
uint16_t key_press_cnt[2] = {0U, 0U};
for (;;)
{
if (FSP_SUCCESS == R_IOPORT_PinRead(&g_ioport_ctrl, BSP_IO_PORT_00_PIN_05, &key_Status[0]))
{
if (key_Status[0] == BSP_IO_LEVEL_LOW)
{
if (key_press_cnt[0] >= 0U)
{
vTaskSuspend(Task_Led_Handle);
}
else
{
key_press_cnt[0] ++;
}
}
else
{
key_press_cnt[0] = 0U;
}
}
if (FSP_SUCCESS == R_IOPORT_PinRead(&g_ioport_ctrl, BSP_IO_PORT_00_PIN_06, &key_Status[1]))
{
if (key_Status[1] == BSP_IO_LEVEL_LOW)
{
if (key_press_cnt[1] >= 4U)
{
vTaskResume(Task_Led_Handle);
}
else
{
key_press_cnt[1] ++;
}
}
else
{
key_press_cnt[1] = 0U;
}
}
vTaskDelay(pdMS_TO_TICKS(10));
}
}
void vApplicationGetIdleTaskMemory(StaticTask_t ** ppxIdleTaskTCBBuffer,
StackType_t ** ppxIdleTaskStackBuffer,
uint32_t * pulIdleTaskStackSize)
{
*ppxIdleTaskTCBBuffer = &xIdleTaskTcb;
*ppxIdleTaskStackBuffer = xIdleTaskStack;
*pulIdleTaskStackSize = 1024;
}
void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer,
StackType_t **ppxTimerTaskStackBuffer,
uint32_t *pulTimerTaskStackSize)
{
*ppxTimerTaskTCBBuffer = &xTimerTaskTcb;
*ppxTimerTaskStackBuffer = xTiemrTaskStack;
*pulTimerTaskStackSize = 2048;
}
void hal_entry(void)
{
Task_Led_Handle = xTaskCreateStatic(Task_LedRunning,
"Led",
1024,
NULL,
4,
xTaskLedStack,
&xTaskLedTcb);
Task_Key_Handle = xTaskCreateStatic(Task_KeyRunning,
"Key",
1024,
NULL,
3,
xTaskKeyStack,
&xTaskKeyTcb);
if (NULL != Task_Led_Handle)
{
vTaskStartScheduler();
}
while (1) {}
#if BSP_TZ_SECURE_BUILD
R_BSP_NonSecureEnter();
#endif
}
void R_BSP_WarmStart(bsp_warm_start_event_t event)
{
if (BSP_WARM_START_RESET == event)
{
#if BSP_FEATURE_FLASH_LP_VERSION != 0
R_FACI_LP->DFLCTL = 1U;
#endif
}
if (BSP_WARM_START_POST_C == event)
{
R_IOPORT_Open (&g_ioport_ctrl, g_ioport.p_cfg);
}
}
#if BSP_TZ_SECURE_BUILD
BSP_CMSE_NONSECURE_ENTRY void template_nonsecure_callable ();
BSP_CMSE_NONSECURE_ENTRY void template_nonsecure_callable ()
{
}
#endif
3.3.1 设置输出hex文件
3.3.2 编译
3.3.3 下载hex文件
打开Renesas Flash Programmer,点击File->New Project,做如下配置。
主要是配置微控制器类型,工程名字,工程目录以及串口端口。
配置完成之后点击Connect,此时会连接失败,如下图
需要按住Reset按钮,之后点击Connect,在松手。
配置Boot
如果使用串口下载,需要配置一下单片机上面的boot跳线帽,切换为SCI/USB BOOT模式如下:
开发板上也有描述,下载完成之后需要将跳线帽变回Interrnal Flash模式。
下载hex文件到单片机
如下图,选择hex文件,然后按下Reset按钮,电机Start,松开Reset按钮,等待下载完成即可。
4. 效果展示
- 系统上电,LED1,LED2,LED3按照亮灭,亮灭,亮灭的状态流水灯显示,流水灯切换周期为500ms;
- 按下按键SW1,流水灯停止;
- 按下按键SW2,流水灯继续。
5. 总结