定义IO初始化结构体

描述

欢迎回到我们的RA系列FSP库开发实战指南频道,下面我们将继续讲解“自己写库——构建库函数雏形”部分:

8.2.5定义IO初始化结构体

由上述IOPORT相关功能的枚举类型我们可以知道,在对IOPORT模块进行初始化时需要根据情况配置它们。因此我们定义一个IOPORT初始化的结构体类型IOPORT_Init_t,它的成员包括了由上述所有枚举类型所声明的变量,因此该结构体类型的变量可以包含IOPORT的相关功能配置。

列表5:代码清单8-4:ra_ioport.h文件

左右滑动查看完整内容

 

/* IOPORT 初始化结构体类型定义 */


typedefstruct
{
IO_Port_t Port;
IO_Pin_t Pin;
IO_Mode_t Mode;
IO_Dir_t Dir;
IO_OType_t OType;
IO_DriveCapability_t Drive;
IO_Level_t Level;
IO_Pull_t Pull;
} IOPORT_Init_t;

 

8.2.6编写IO操作函数

我们把IO操作函数的声明和IO初始化函数的声明都放在ra_ioport.h头文件。

列表6:代码清单8-5:ra_ioport.h文件

左右滑动查看完整内容

 

/* IO 操作函数(调用一次只能操作一个 IO 引脚) */
uint32_tIOPORT_PinRead(IO_Port_t port, IO_Pin_t pin);
voidIOPORT_PinWrite(IO_Port_t port, IO_Pin_t pin, IO_Level_t␣
→level);
voidIOPORT_PinToggle(IO_Port_t port, IO_Pin_t pin);
voidIOPORT_PinAccessEnable(void);
voidIOPORT_PinAccessDisable(void);


/* IO 初始化函数(调用一次只能初始化一个 IO 引脚) */
voidIOPORT_Init(IOPORT_Init_t *ioport_init);

 

然后在ra_ioport.c源文件里面实现这些IO操作函数。

列表7:代码清单8-6:ra6m5_ioport.c文件

左右滑动查看完整内容

 

/* 读引脚电平 */


uint32_tIOPORT_PinRead(IO_Port_t port, IO_Pin_t pin)
{
/* Read pin level. */
return R_PFS->PORT[port >> 8].PIN[pin].PmnPFS_b.PIDR;
}


/* 写引脚电平 */
voidIOPORT_PinWrite(IO_Port_t port, IO_Pin_t pin, IO_Level_t level)
{
uint32_t pfs_bits = R_PFS->PORT[port >> 8].PIN[pin].PmnPFS; //读寄存器␣
→PmnPFS


pfs_bits &= ~(uint32_t)0x1; //清零 PODR 位
R_PFS->PORT[port >> 8].PIN[pin].PmnPFS = (pfs_bits | level);
}


/* 翻转引脚电平 */
voidIOPORT_PinToggle(IO_Port_t port, IO_Pin_t pin)
{
uint32_t pfs_bits = R_PFS->PORT[port >> 8].PIN[pin].PmnPFS; //读寄存器␣
→PmnPFS
pfs_bits ^= (uint32_t)0x1; //取反 PODR 位
R_PFS->PORT[port >> 8].PIN[pin].PmnPFS = pfs_bits;
}


/* 引脚访问使能 */
voidIOPORT_PinAccessEnable(void)
{
R_PMISC->PWPR = 0; ///< Clear BOWI bit - writing to PFSWE bit␣
→enabled
R_PMISC->PWPR = 1U << 6U; ///< Set PFSWE bit - writing to PFS register␣
→enabled
}


/* 引脚访问禁止 */
voidIOPORT_PinAccessDisable(void)
{
R_PMISC->PWPR = 0; ///< Clear PFSWE bit - writing to PFS register␣
→disabled
R_PMISC->PWPR = 1U << 7U; ///< Set BOWI bit - writing to PFSWE bit␣
→disabled
}

 

8.2.7编写IO初始化函数

最后编写IOPORT初始化函数。

列表8:代码清单8-7:ra_ioport.c文件

左右滑动查看完整内容

 

/* IOPORT 初始化函数 */


voidIOPORT_Init(IOPORT_Init_t *ioport_init)
{
uint32_t pfs_bits = 0; //不读取寄存器 PmnPFS
if(ioport_init->Mode == IO_MODE_GPIO) //如果引脚用作普通 GPIO 功能
{
if(ioport_init->Dir == IO_DIR_INPUT) /* 用作输入模式 */
{
pfs_bits |= (ioport_init->Pull) << 4; //设置输入上拉
}
elseif(ioport_init->Dir == IO_DIR_OUTPUT) /* 用作输出模式 */
{
pfs_bits |= (ioport_init->Dir) << 2; //设置为输出
pfs_bits |= (ioport_init->Level) << 0; //设置输出电平
pfs_bits |= (ioport_init->Mode) << 6; //设置输出模式
pfs_bits |= (ioport_init->Drive) << 10; //设置输出驱动能力
}
}
else
{
//我们不考虑引脚用作复用模式和模拟输入输出模式的情况
//也不考虑中断的情况,仅考虑普通的 GPIO 输入输出功能
}


/* 写入配置到寄存器 PmnPFS */
R_PFS->PORT[ioport_init->Port >> 8].PIN[ioport_init->Pin].PmnPFS = pfs_
→bits;
}

 

8.2.8hal_entry入口函数

前一章节实验里有讲过,当使用RTOS时,程序从main函数开始进行线程调度;当没有使用RTOS时,C语言程序的入口函数main函数调用了hal_entry函数。本章节实验的工程也是没有选用RTOS的,因此,用户程序是从hal_entry函数开始执行。

打开“srchal_entry.c”文件,我们在“hal_entry.c”文件中添加对头文件“ra_ioport.h”的包含,然后在hal_entry函数里面编写我们的代码。

以启明6M5开发板为例,RA6M5工程的hal_entry数代码如下所示。

注解

启明4M2开发板和启明2L1开发板的用户可直接打开配套的“09_Register_MyLib”例程查看该代码,限于篇幅,不在本章中贴出。

列表9:代码清单8-8:hal_entry.c文件

左右滑动查看完整内容

 

/* IOPORT 模块头文件 (自己写库——构建库函数雏形) */
#include"ioport/ra_ioport.h"


voidhal_entry(void)
{
/* TODO: add your own code here */


/* 调用取消写保护函数 */
IOPORT_PinAccessEnable();


/* 使用 IOPORT 初始化结构体和调用初始化函数来配置 PFS 寄存器 */
IOPORT_Init_t led_io_init;
led_io_init.Port = IO_PORT_04;
led_io_init.Pin = IO_PIN_00;
led_io_init.Mode = IO_MODE_GPIO; //普通 GPIO 模式,而不是复用功能模式或其他
的
led_io_init.Dir = IO_DIR_OUTPUT;
led_io_init.OType = IO_OTYPE_PP;
led_io_init.Drive = IO_DRIVE_LOW;
led_io_init.Level = IO_LEVEL_HIGH; //输出高电平(LED 熄灭)
//LED_IO_Init.Pull = IO_NO_PULL; //端口方向处于输出模式下是用不了上拉的,所以这
个属性没意义
IOPORT_Init(&led_io_init); //调用初始化函数,进行 LED1 引脚初始化
led_io_init.Pin = IO_PIN_03; //更换引脚号
IOPORT_Init(&led_io_init); //结构体其他属性不变,再次调用初始化函数,进行 LED2 引
脚初始化
led_io_init.Pin = IO_PIN_04; //更换引脚号
IOPORT_Init(&led_io_init); //结构体其他属性不变,再次调用初始化函数,进行 LED3 引
脚初始化


/** 此时 3 个 LED 灯的引脚默认输出的是高电平,所以 3 个 LED 灯都会默认不亮
* 我们先打开所有 LED 灯,然后在 while 循环里让 LED1 闪烁:每秒钟翻转一次状态
*/
IOPORT_PinWrite(IO_PORT_04, IO_PIN_00, IO_LEVEL_LOW); //点亮 LED1
IOPORT_PinWrite(IO_PORT_04, IO_PIN_03, IO_LEVEL_LOW); //点亮 LED2
IOPORT_PinWrite(IO_PORT_04, IO_PIN_04, IO_LEVEL_LOW); //点亮 LED3


while(1)
{
/* 使用函数 IOPORT_PinToggle 翻转 LED1 引脚电平 */
IOPORT_PinToggle(IO_PORT_04, IO_PIN_00);
R_BSP_SoftwareDelay(1000, BSP_DELAY_UNITS_MILLISECONDS);
}


#if BSP_TZ_SECURE_BUILD
/* Enter non-secure code */
R_BSP_NonSecureEnter();
#endif
}

 

8.3下载验证

编写好上述代码,然后将程序编译并下载到开发板之后,按下复位按键来复位开发板,可以观察到实验现象与上一章的实验现象相同:开发板上面除了电源指示灯之外的3个LED灯当中有两个灯常亮,还有一个灯在缓慢闪烁。闪烁着的LED灯为LED1,它每秒钟(1000毫秒)便改变一次亮灭的状态。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分