0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

如何用C语言操作寄存器——瑞萨RA系列FSP库开发实战指南(10)

瑞萨嵌入式小百科 来源:瑞萨MCU小百科 2025-04-22 15:30 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

3.4

如何用C语言操作寄存器

3.4.1

C语言对寄存器的封装

前面的所有关于存储器映射的内容,最终都是为大家更好地理解如何用C语言控制读写外设寄存器做准备,因此此处是本章的重点内容。

3.4.1.1

外设模块基地址定义

编程上为了方便理解和记忆,我们要把外设模块基地址以相应的宏定义起来,外设基地址都以它们的名字作为宏名的组成部分。以下是IO端口外设基地址的宏定义。

列表1:代码清单3‑1 IOPORT外设基地址宏定义

左右滑动查看完整内容

/* 外设基地址 */
#defineR_PORT0_BASE 0x40080000
#defineR_PORT1_BASE 0x40080020
#defineR_PORT2_BASE 0x40080040
#defineR_PORT3_BASE 0x40080060
#defineR_PORT4_BASE 0x40080080
#defineR_PORT5_BASE 0x400800A0
#defineR_PORT6_BASE 0x400800C0
#defineR_PORT7_BASE 0x400800E0
#defineR_PORT8_BASE 0x40080100
#defineR_PORT9_BASE 0x40080120
#defineR_PORT10_BASE 0x40080140
#defineR_PORT11_BASE 0x40080160
#defineR_PFS_BASE 0x40080800
#defineR_PMISC_BASE 0x40080D00

3.4.1.2

寄存器结构体定义

由于寄存器的数量是非常之多的,如果每个寄存器都用像*((uint32_t*)(0x40080000+0x0020*1))这样的方式去访问的话,会显得很繁琐、很麻烦。为了更方便地访问寄存器,我们会借助C语言结构体的特性去定义寄存器和寄存器位域,这是通用的做法。

列表2:代码清单3‑2使用结构体封装外设寄存器

左右滑动查看完整内容

// 注:关于输入输出端口的声明
/* C 语言: IO definitions (access restrictions to peripheral registers) */
//#define __I volatile const /*!< Defines 'read only'␣
,
→permissions */
//#define __O volatile /*!< Defines 'write only'␣
,
→permissions */
//#define __IO volatile /*!< Defines 'read / write'␣
,
→permissions */


/* 下面的宏定义用于结构体成员 */
/* following defines should be used for structure members */
//#define __IM volatile const /*! Defines 'read only'␣
,
→structure member permissions */
//#define __OM volatile /*! Defines 'write only'␣
,
→structure member permissions */
//#define __IOM volatile /*! Defines 'read / write'␣
,
→structure member permissions */


//typedef unsigned char uint8_t;
//typedef unsigned short int uint16_t; /* 无符号 16 位整型变量 */
//typedef unsigned int uint32_t; /* 无符号 32 位整型变量 */


/**
* @brief I/O Ports (R_PORT0)
*/
typedefstruct /*!< (@ 0x40040000) R_PORT0␣
,
→Structure */
{
union
{
union
{
__IOM uint32_t PCNTR1; /*!< (@ 0x00000000) Port Control␣
,
→Register 1 */


struct
{
__IOM uint32_t PDR : 16; /*!< [15..0] Pmn Direction(引脚
Pmn 方向)*/
__IOM uint32_t PODR : 16; /*!< [31..16] Pmn Output Data(引脚
Pmn 输出数据)*/
} PCNTR1_b;
};
/* ... 代码过长省略 ... */
};


union
{
union
{
__IM uint32_t PCNTR2; /*!< (@ 0x00000004) Port Control␣
,
→Register 2 */


struct
{
__IM uint32_t PIDR : 16; /*!< [15..0] Pmn Input Data(引脚
Pmn 输入数据)*/
__IM uint32_t EIDR : 16; /*!< [31..16] Pmn Event Input Data
(引脚 Pmn 事件输入数据)*/
} PCNTR2_b;
};


/* ... 代码过长省略 ... */
};


union
{


union
{
__OM uint32_t PCNTR3; /*!< (@ 0x00000008) Port Control␣
,
→Register 3 */
struct
{
__OM uint32_t POSR : 16; /*!< [15..0] Pmn Output Set(引脚
Pmn 输出置位)*/
__OM uint32_t PORR : 16; /*!< [31..16] Pmn Output Reset(引脚
Pmn 输出复位)*/
} PCNTR3_b;
};


/* ... 代码过长省略 ... */
};


union
{
union
{
__IOM uint32_t PCNTR4; /*!< (@ 0x0000000C) Port Control␣,
→Register 4 */


struct
{
__IOM uint32_t EOSR : 16; /*!< [15..0] Pmn Event Output Set
(引脚 Pmn 事件输出置位)*/
__IOM uint32_t EORR : 16; /*!< [31..16] Pmn Event Output␣
→Reset(引脚 Pmn 事件输出复位)*/
} PCNTR4_b;
};


/* ... 代码过长省略 ... */
};
} R_PORT0_Type; /*!< Size = 16 (0x10) */

3.4.1.3

外设模块寄存器定义

我们在上一步已经定义好了R_PORT0_Type类型的结构体,它包含了IOPORT的寄存器定义。接下来使用宏定义来表示结构体指针,指针指向IOPORT外设的每个端口的寄存器首地址。

列表3:代码清单3‑3寄存器定义

#defineR_PORT0 ((R_PORT0_Type *) R_PORT0_BASE)
#defineR_PORT1 ((R_PORT0_Type *) R_PORT1_BASE)
#defineR_PORT2 ((R_PORT0_Type *) R_PORT2_BASE)
#defineR_PORT3 ((R_PORT0_Type *) R_PORT3_BASE)
#defineR_PORT4 ((R_PORT0_Type *) R_PORT4_BASE)
#defineR_PORT5 ((R_PORT0_Type *) R_PORT5_BASE)
#defineR_PORT6 ((R_PORT0_Type *) R_PORT6_BASE)
#defineR_PORT7 ((R_PORT0_Type *) R_PORT7_BASE)
#defineR_PORT8 ((R_PORT0_Type *) R_PORT8_BASE)
#defineR_PORT9 ((R_PORT0_Type *) R_PORT9_BASE)
#defineR_PORT10 ((R_PORT0_Type *) R_PORT10_BASE)

这样便大功告成了,我们就可以使用这些宏来访问各个IO端口的每一个寄存器了。

3.4.2

修改寄存器操作的本质:读-改-写

有了以上的对IOPORT这个外设模块的寄存器的定义,我们便完成了“C语言对寄存器的封装”这个步骤,接下来我们便可以使用C语言对寄存器进行各种操作了。

对寄存器进行操作可以是忽略寄存器原本的值,而直接覆盖写入新的值;但是更为一般的操作是根据原本的寄存器值进行修改,即:先读出寄存器原本的值,然后修改该值,最后重新写入到寄存器里面,让新的值生效。

接下来将介绍修改寄存器的几种通用方法。

3.4.2.1

清零寄存器上的某N个位

使用C语言的按位与“&”运算符可以将位进行清零。

列表4:代码清单3‑4位清零:按位与&

//清零某个位
R_PORT0->PODR &= ~(1u<<0); //清零 PODR 寄存器的第 0 位
R_PORT0->PODR &= ~(1u<<6); //清零 PODR 寄存器的第 6 位


//清零多个位
R_PORT0->PODR &= ~(3u<<0); //清零 PODR 寄存器的第 0,1 位
R_PORT0->PODR &= ~(3u<<6); //清零 PODR 寄存器的第 6,7 位

3.4.2.2

对寄存器上的某N个位进行置位

使用C语言的按位或“|”运算符可以将位进行置一。

列表5:代码清单3‑5位置位:按位或|

//置位某个位
R_PORT0->PODR |= 1u<<0; //PODR 寄存器的第 0 位置 1
R_PORT0->PODR |= 1u<<6; //PODR 寄存器的第 6 位置 1


//置位多个位
R_PORT0->PODR |= 3u<<0; //PODR 寄存器的第 0,1 位置 1
R_PORT0->PODR |= 3u<<6; //PODR 寄存器的第 6,7 位置 1

3.4.2.3

对寄存器上的某N个位进行取反

使用C语言的按位异或“^”运算符可以将位进行取反。

列表6:代码清单3‑6位取反:按位异或^

//取反某个位
R_PORT0->PODR ^= 1u<<0; //取反 PODR 寄存器的第 0 位
R_PORT0->PODR ^= 1u<<6; //取反 PODR 寄存器的第 6 位


//取反多个位
R_PORT0->PODR ^= 3u<<0; //取反 PODR 寄存器的第 0,1 位
R_PORT0->PODR ^= 3u<<6; //取反 PODR 寄存器的第 6,7 位

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

    关注

    147

    文章

    18643

    浏览量

    388266
  • 寄存器
    +关注

    关注

    31

    文章

    5590

    浏览量

    129158
  • 瑞萨
    +关注

    关注

    36

    文章

    22434

    浏览量

    89839
  • C语言
    +关注

    关注

    183

    文章

    7642

    浏览量

    144696
  • FSP
    FSP
    +关注

    关注

    0

    文章

    47

    浏览量

    7664
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    RA系列MCU FSP开发实战指南(09)存储映射

    3.3 存储映射 前文所述,寄存器与RAM、FLASH一样都是芯片内部的一种存储设备。那么,当我们需要访问它们的时候,我们需要知道它们的存储地址。 3.3.1 存储映射表 如下图所示为RA
    的头像 发表于 04-16 15:52 1301次阅读
    <b class='flag-5'>瑞</b><b class='flag-5'>萨</b><b class='flag-5'>RA</b><b class='flag-5'>系列</b>MCU <b class='flag-5'>FSP</b><b class='flag-5'>库</b><b class='flag-5'>开发</b><b class='flag-5'>实战</b><b class='flag-5'>指南</b>(09)存储<b class='flag-5'>器</b>映射

    RA系列FSP开发实战指南(19)使用寄存器点亮LED灯

    野火启明6M5开发板的LED电路图如图所示。图中RA6M5芯片的P400、P403、P404引脚分别通过一个2.2 KΩ的限流电阻连接到LED1、LED2、LED3这三个用户LED灯的阴极,LED灯的阳极连接到3.3V电源。而LED4是电源指示灯,只要
    的头像 发表于 06-11 15:06 1776次阅读
    <b class='flag-5'>瑞</b><b class='flag-5'>萨</b><b class='flag-5'>RA</b><b class='flag-5'>系列</b><b class='flag-5'>FSP</b><b class='flag-5'>库</b><b class='flag-5'>开发</b><b class='flag-5'>实战</b><b class='flag-5'>指南</b>(19)使用<b class='flag-5'>寄存器</b>点亮LED灯

    e2studio(1)----芯片之搭建FSP环境

    视频教学 样品申请 请勿添加外链 e2studio软件 e2studio是的集成开发环境,FSP 提供了众多可提高效率的工具,用于开发
    发表于 09-30 15:28

    RA2L1入门学习】RA2L1开发环境搭建

    e² studio 和 FSP 的下载、安装及使用指南 1. 什么是 e² studio 和 FSP? e² studio 是电子(Re
    发表于 03-07 11:33

    RA4系列开发板体验】开发环境搭建和新手点灯指南

    RA4系列开发板体验】开发环境搭建和新手点灯指南
    发表于 11-24 22:54

    RA4系列开发板体验】Keil开发环境搭建+初探IO操作

    前言: 非常感谢电子发烧友和生态工作室能够给这次试用开发板的机会,后续根据生RA态工作室提供的资料进行功能测试。此篇根据RA Smart
    发表于 11-29 14:50

    RA4系列开发板体验】10. 我的试用总结

    之前发帖:【RA4系列开发板体验】1. 新建工程+按键控制LED【
    发表于 12-10 22:34

    RA4系列开发板体验】体验过程

    、使用 RASC 生成 Keil 工程+点亮LED参照“ 【RA4系列开发板体验】2. 使用RASC 生成 Keil 工程+点亮LED
    发表于 12-18 16:20

    【野火启明6M5开发板体验】开箱+认识开发板+资料

    按键检测29. WiFi——模块通讯板尺寸:3、资料:*附件:[野火EmbedFire]《RA系列FSP
    发表于 12-20 23:28

    C语言寄存器操作

    C语言寄存器操作
    发表于 01-13 12:56 6次下载
    <b class='flag-5'>C</b><b class='flag-5'>语言</b>:<b class='flag-5'>寄存器</b><b class='flag-5'>操作</b>

    C语言操作寄存器的常见手法

    使用C语言寄存器赋值时,常常需要用到C语言的位操作方法。把
    的头像 发表于 03-12 09:06 4007次阅读

    【有奖直播预报名】电子RA系列产品开发工具之FSP4.0.0新特性介绍

    为使用电子RA系列ARM微控制的嵌入式系统设计提供简单易用且可扩展的高质量软件。 直播主题
    的头像 发表于 11-22 12:20 1340次阅读

    【视频教程】RA单片机FSP开发(3)FSP架构-解释Blinky架构[上]

    干货分享 前篇回顾 【视频教程】RA单片机FSP开发(1)环境搭建(带RASC) 【视频教程】
    的头像 发表于 12-06 12:15 1633次阅读

    使用e² studio FSP基于RA2E1定时配置PWM输出

    使用e² studio FSP基于RA2E1定时配置PWM输出
    的头像 发表于 08-01 00:13 1682次阅读
    使用<b class='flag-5'>瑞</b><b class='flag-5'>萨</b>e² studio <b class='flag-5'>FSP</b>基于<b class='flag-5'>RA</b>2E1定时<b class='flag-5'>器</b>配置PWM输出

    电子RA系列微控制的可扩展性强的配置软件包 (FSP)安装下载与使用指南

    电子RA系列微控制的可扩展性强的配置软件包 (FSP)安装下载与使用
    的头像 发表于 06-11 17:21 1426次阅读