打印
[新手园地]

学习体会第四贴——Timer应用之理解C语言位域

[复制链接]
4311|6
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
gdmgb520|  楼主 | 2011-9-18 17:42 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 gdmgb520 于 2011-9-18 17:46 编辑

函数调用

DrvSYS_SelectIPClockSource(E_SYS_TMR0_CLKSRC,0);


查看API手册可知,该函数的作用是给某个设备选择时钟源。该函数有两个参数,第一个参数指定外设,第二个指定时钟源。
  
u8ClkSrcSel

  
  
0

  
  
1

  
  
2

  
  
3

  
  
7

  
  
Watch Dog Timer

  
  
Reserved

  
  
Ext. 32K (*)

  
  
HCLK/2048

  
  
Internal 10K

  
  
X

  
  
ADC

  
  
External 12M

  
  
PLL

  
  
HCLK (*)

  
  
Internal 22M

  
  
X

  
  
Timer

  
  
External 12M

  
  
External 32K

  
  
HCLK

  
  
Reserved

  
  
Internal 22M

  
  
UART

  
  
External 12M

  
  
PLL

  
  
Reserved

  
  
Internal 22M

  
  
X

  
  
PWM

  
  
External 12M

  
  
External 32K

  
  
HCLK

  
  
Internal 22M

  
  
X

  
  
Frequency  Divider Output

  
  
External 12M

  
  
External 32K

  
  
HCLK

  
  
Internal 22M

  
  
X

  
  
I2S

  
  
External 12M

  
  
PLL

  
  
HCLK

  
  
Internal 22M

  
  
X

  
所以,该函数调用的作用是给Timer0选择外部12MHz时钟源。


进一步查看该函数的内部结构:
int32_t DrvSYS_SelectIPClockSource(E_SYS_IP_CLKSRC eIpClkSrc, uint8_t u8ClkSrcSel)

{
       switch(eIpClkSrc)
       {
              ……
              case E_SYS_TMR0_CLKSRC:
                  SYSCLK->CLKSEL1.TMR0_S = u8ClkSrcSel;
                     break;
              ……
              default:
                     return E_DRVSYS_ERR_IPSRC;
       }
       return E_SUCCESS;
}
SYSCLK->CLKSEL1.TMR0_S
这里我疑惑了。下面来一探其究竟。

首先,SYSCLK 是什么
#define SYSCLK      ((SYSCLK_T *) SYSCLK_BASE)
可见,SYSCLK 是一个 SYSCLK_T 类型的指针,物理地址是 SYSCLK_BASE


1.SYSCLK_T结构体类型
typedef struct
{
SYSCLK_PWRCON_T    PWRCON;
SYSCLK_AHBCLK_T    AHBCLK;
SYSCLK_APBCLK_T    APBCLK;
SYSCLK_CLKSTATUS_T CLKSTATUS;
SYSCLK_CLKSEL0_T   CLKSEL0;
SYSCLK_CLKSEL1_T   CLKSEL1;
SYSCLK_CLKDIV_T    CLKDIV;
SYSCLK_CLKSEL2_T   CLKSEL2;
SYSCLK_PLLCON_T    PLLCON;
SYSCLK_FRQDIV_T    FRQDIV;
} SYSCLK_T;
2.物理地址SYSCLK_BASE
#define SYSCLK_BASE          (AHB_BASE       + 0x00200)
#define AHB_BASE            ((     uint32_t)0x50000000)
所以,SYSCLK_BASE代表的地址是0x5000_0x0200


3.成员变量的地址

而在SYSCLK_T 结构体中每个成员都是4字节,所以,CLKSEL1 成员变量位于该结构体中的 0x14位置。
故,SYSCLK->CLKSEL1的实际地址就是0x5000_0214。从数据手册知道这就是CLKSEL1寄存器的地址。


其次,SYSCLK->CLKSEL1.TMR0_S是什么
SYSCLK_T
结构体定义中可以看到:
SYSCLK_CLKSEL1_T   CLKSEL1;
SYSCLK_CLKSEL1_T的定义如下:
typedef struct

{
__IO uint32_t  WDT_S:2;
__IO uint32_t  ADC_S:2;
__I  uint32_t  RESERVE1:4;
__IO
uint32_t  TMR0_S:3;
__I  uint32_t  RESERVE2:1;
__IO uint32_t  TMR1_S:3;
__I  uint32_t  RESERVE3:1;
__IO uint32_t  TMR2_S:3;
__I  uint32_t  RESERVE4:1;
__IO uint32_t  TMR3_S:3;
__I  uint32_t  RESERVE5:1;
__IO uint32_t  UART_S:2;
__IO uint32_t  CAN_S:2;
__IO uint32_t  PWM01_S:2;
__IO uint32_t  PWM23_S:2;
} SYSCLK_CLKSEL1_T;
这东东看起来是一个结构体,但实际上这是C语言的位域定义(关于位域的具体内容可以参考《谭浩强 C语言 第三版 12.2节》)。从该定义中知道位域名TMR0_S占用3各位,8-10bit


最后把以上各个片段拼起来:
SYSCLK->CLKSEL1.TMR0_S = u8ClkSrcSel;
SYSCLK SYSCLK_T型结构体指针,该类型结构体包含10个变量,均为4字节,指向地址为0x50000000
CLKSEL1 :上述结构体的第六个成员变量,其类型是一个SYSCLK_CLKSEL1_T位域结构,该结构总长度为4字节。
TMR0_S CLKSEL1位域结构中的一个位域,8-10bit


至于你明白没有,反正我是明白了。
不对的地方请指正啊。

相关帖子

沙发
hotpower| | 2011-9-19 06:10 | 只看该作者
学习刘应该如此!

使用特权

评论回复
板凳
gdmgb520|  楼主 | 2011-9-19 13:13 | 只看该作者
谢谢大叔鼓励。

使用特权

评论回复
地板
huzaizai007| | 2012-3-5 15:35 | 只看该作者
好贴,很清楚
需要复习c语言了……

使用特权

评论回复
5
ljp98| | 2012-7-25 11:02 | 只看该作者
谢谢楼主,希望多看到几个这样的好贴。

使用特权

评论回复
6
fxyc87| | 2012-8-21 14:44 | 只看该作者
问个问题
NUC IO是可以有单位的位访问寄存器,比LPC的M0稍方便点,有点51的感觉
那所有寄存器都可以以位方式访问进行读写么?

使用特权

评论回复
7
188598686| | 2013-11-7 11:15 | 只看该作者
#define SYSCLK      ((SYSCLK_T *) SYSCLK_BASE)
可见,SYSCLK 是一个 SYSCLK_T 类型的指针,物理地址是 SYSCLK_BASE。

这个在C语言里有介绍吗?没看明白啊~~~
结构体指针(SYSCLK_T *)的物理地址 SYSCLK_BASE可以直接写在后面啊?我的C语言没学好,哎哎~~求楼主科普一下,谢谢啊

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:了解新东西才知道自己的不足。 www.elecbench.com

67

主题

452

帖子

1

粉丝