精华内容
下载资源
问答
  • //忘寄存器地址0x80赋值0x00 sfr是一种扩充数据类型,点用一个内存单位,值域为0-255.利用它可以访问51单片机内部所有的特殊功能寄存器。前一句“sfr p0=0x80”就是将P0映射到地址0x80。后一句“p0=0x00”就是往p0...

    1  51单片机访问地址

    sfr P0 =0x80;   //P0映射到地址0x80
    P0=0x00;        //忘寄存器地址0x80赋值0x00

            sfr是一种扩充数据类型,点用一个内存单位,值域为0-255.利用它可以访问51单片机内部所有的特殊功能寄存器。前一句“sfr p0=0x80”就是将P0映射到地址0x80。后一句“p0=0x00”就是往p0地址(0x80)代表的寄存器写值。

    2  STM32单片机访问地址

            对MCU,一切底层配置,最终都是配置寄存器。我们知道,存储器本身没有地址,给存储器分配地址的过程叫存储器映射,那什么叫寄存器映射?寄存器到底是什么?

            在存储器Block2 这块区域,设计的是片上外设,它们以四个字节为一个单元,共32bit,每一个单元对应不同的功能,当我们控制这些单元时就可以驱动外设工作。我们可以找到每个单元的起始地址,然后通过C 语言指针的操作方式来访问这些单元,如果每次都是通过这种地址的方式来访问,不仅不好记忆还容易出错,这时我们可以根据每个单元功能的不同,以功能为名给这个内存单元取一个别名,这个别名就是我们经常说的寄存器,这个给已经分配好地址的有特定功能的内存单元取别名的过程就叫寄存器映射。

            比如,我们找到GPIOB 端口的输出数据寄存器ODR 的地址是0x4001 0C0C(至于这个地址如何找到可以先跳过,后面我们会有详细的讲解),ODR 寄存器是32bit,低16bit有效,对应着16 个外部IO,写0/1 对应的的IO 则输出低/高电平。现在我们通过C 语言指针的操作方式,让GPIOB 的16 个IO 都输出高电平。

    *(unsigned int*)(0x4001 0C0C) = 0xFFFF FFFF;    // GPIOB端口全部输出高电平

            0x4001 0C0C 在我们看来是GPIOB 端口ODR 的地址,但是在编译器看来,这只是一个普通的变量,是一个立即数,要想让编译器也认为是指针,我们得进行强制类型转换,把它转换成指针,即(unsigned int *)0x4001 0C0C,然后再对这个指针进行 * 操作。刚刚我们说了,通过绝对地址访问内存单元不好记忆且容易出错,我们可以通过寄存器的方式来操作。

    #define  GPIOB_ODR  (unsigned int*)(GPIOB_BASE+0x0C)
    *GPIOB_ODR = 0xFFFF FFFF;  // GPIOB 端口全部输出 高电平

            为了方便操作,我们干脆把指针操作“*”也定义到寄存器别名里面。

    #define  GPIOB_ODR * (unsigned int*)(GPIOB_BASE+0x0C)
    GPIOB_ODR = 0xFFFF FFFF;   // GPIOB 端口全部输出 高电平

            GPIOB->ODR=0xFFFF FFFF; 
                     值0xFFFF FFFF是怎么赋值给了GPIOB的ODR寄存器地址的呢?也就是说GPIOB->ODR这种写法,是怎么与GPIOB的ODR寄存器地址映射起来的?       
            寄存器地址名称映射:STM32肯定也是可以这样来设置寄存器的。但是由于STM32的寄存器数目太多了,如果以这样的方式列出来,需要很大的篇幅,而且也不方便开发。所以,MDK采用的方式是通过结构体来将寄存器组织在一起。下面就介绍MDK如何把结构体和地址对应起来的,为什么修改结构体成员变量的值就可以达到操作寄存器的值?这些事情都是在stm32f10x.h文件中完成的。

            定义在stm32f10x.h文件和stm32f4xx.h

    typedef struct                             typedef struct
    {                                          {
      __IO uint32_t CRL;                         __IO uint32_t MODER;  
      __IO uint32_t CRH;                         __IO uint32_t OTYPER;   
      __IO uint32_t IDR;                         __IO uint32_t OSPEEDR; 
      __IO uint32_t ODR;                         __IO uint32_t PUPDR;  
      __IO uint32_t BSRR;                        __IO uint32_t IDR;   
      __IO uint32_t BRR;                         __IO uint32_t ODR; 
      __IO uint32_t LCKR;                        __IO uint16_t BSRRL;   
    } GPIO_TypeDef;                              __IO uint16_t BSRRH; 
                                                 __IO uint32_t LCKR;  
                                                 __IO uint32_t AFR[2]; 
                                               } GPIO_TypeDef;

            stm32f10x.h一组GPIO有7个成员变量,设GPIOA的基地址为A,成员变量GPIO->CRL偏移值B,则GPIO->CRL的地址就是A+B。GPIOA的基地址挂载在总线APB2,以APB2的基地址加上GPIOA相对于APB2的偏移量(是常量)得到GPIOA的地址GPIOA_BASE。APB2的基地址挂载在外设基地址,以外设基地址加上APB2的基地址相对于外设基地址的偏移量(是常量)得到APB1的基地址AHB1PERIPH_BASE。外设基地址一般定义为基地址PERIPH_BASE先定义一个外设基地址,再定义总线APB2的基地址,再定义GPIO的基地址,再定义GPIOA的寄存器的地址。

            stm32f10x.h的第1274行定义的外设基地址:

    #define PERIPH_BASE           ((uint32_t)0x40000000)

            stm32f10x.h的第1282行定义的APB1、APB2和AHB外设基地址,片上外设区分为三条总线,根据外设速度的不同,不同总线挂载着不同的外设,APB1挂载低速外设,APB2 和AHB 挂载高速外设。相应总线的最低地址我们称为该总线的基地址,总线基地址也是挂载在该总线上的首个外设的地址。其中APB1 总线的地址最低,片上外设从这里开始,也叫外设基地址。

    #define APB1PERIPH_BASE       PERIPH_BASE
    #define APB2PERIPH_BASE       (PERIPH_BASE + 0x10000)
    #define AHBPERIPH_BASE        (PERIPH_BASE + 0x20000)

            stm32f10x.h的第1315行定义的GPIOA_BASE、GPIOB_BASE、GPIOC_BASE、GPIOD_BASE、GPIOE_BASE、GPIOF_BASE和GPIOG_BASE基地址。总线上挂载着各种外设,这些外设也有自己的地址范围,特定外设的首个地址称为“XX 外设基地址”,也叫XX 外设的边界地址。这里面我们以GPIO 这个外设来讲解外设的基地址,因为GPIO都是挂载在APB2总线之上的,所以它的基地址是由APB2总线的基地址+GPIO在APB2总线上的偏移地址决定的。

    #define GPIOA_BASE            (APB2PERIPH_BASE + 0x0800)
    #define GPIOB_BASE            (APB2PERIPH_BASE + 0x0C00)
    #define GPIOC_BASE            (APB2PERIPH_BASE + 0x1000)
    #define GPIOD_BASE            (APB2PERIPH_BASE + 0x1400)
    #define GPIOE_BASE            (APB2PERIPH_BASE + 0x1800)
    #define GPIOF_BASE            (APB2PERIPH_BASE + 0x1C00)
    #define GPIOG_BASE            (APB2PERIPH_BASE + 0x2000)

            stm32f10x.h的第1408行通过指针强制将GPIOA_BASE、GPIOB_BASE、GPIOC_BASE、GPIOD_BASE、GPIOE_BASE、GPIOF_BASE和GPIOG_BASE转换成指定的GPIOA、GPIOB、GPIOC、GPIOD、GPIOE、GPIOF和GPIOG地址的GPIO_TypeDef类型指针。这句话的意思就是,GPIOA指向地址GPIOA_BASE,而GPIOA_BASE存放的数据类型是GPIO_TypeDef。

    #define GPIOA               ((GPIO_TypeDef *) GPIOA_BASE)
    #define GPIOB               ((GPIO_TypeDef *) GPIOB_BASE)
    #define GPIOC               ((GPIO_TypeDef *) GPIOC_BASE)
    #define GPIOD               ((GPIO_TypeDef *) GPIOD_BASE)
    #define GPIOE               ((GPIO_TypeDef *) GPIOE_BASE)
    #define GPIOF               ((GPIO_TypeDef *) GPIOF_BASE)
    #define GPIOG               ((GPIO_TypeDef *) GPIOG_BASE)

            stm32f10x.h的第1001行定义的有关GPIO的寄存器的结构体变量,结构体里面声明了7个变量,即结构体的7个变量就是GPIOB的7个寄存器。这个时候就明白了“GPIOB->ODR”就是指:GPIOB结构体下的ODR变量。

    typedef struct
    {
      __IO uint32_t CRL;
      __IO uint32_t CRH;
      __IO uint32_t IDR;
      __IO uint32_t ODR;
      __IO uint32_t BSRR;
      __IO uint32_t BRR;
      __IO uint32_t LCKR;
    } GPIO_TypeDef;

            GPIO 有很多个寄存器,每一个都有特定的功能。每个寄存器为32bit,占四个字节,在该外设的基地址上按照顺序排列,寄存器的位置都以相对该外设基地址的偏移地址来描述。这里我们以GPIOB 端口为例,来说明GPIO都有哪些寄存器。

    在这里插入图片描述

           此时可以算出GPIOA的基地址位了:GPIOA_BASE=0x40000000+0x10000+0x0800=0x40010800
            这上面就已经知道了GPIOA的基地址,那么那些GPIOA的7个寄存器的地址又是怎么计算出来的呢?
                    GPIOA的寄存器的地址=GPIOA基地址+寄存器相对GPIOA基地址的偏移值
            寄存器相对于GPIOA基地址的偏移值可以在上面的寄存器地址映射表中查到。稍微解释一下:GPIO的每个寄存器都是32位的,所以每个寄存器是占用4个地址,也就是说一共占用28个地址。地址偏移范围为(000h-01Bh)。这个地址偏移是相对于GPIOA的基地址而言的。那么你可能又有一个疑问:结构体里面的寄存器又是怎么与地址一一对应的呢?这就涉及到结构体的一个特征,那就是结构体存储的成员的地址是连续的。上面讲到GPIOA是指向GPIO_TypeDef类型的指针,又由于GPIO_TypeDef是结构体,所以自然而然我们就可以算出GPIOA指向的结构体成员变量对应地址了。

    3  C 语言对寄存器的封装

    3.1  封装总线和外设基地址

            在编程上为了方便理解和记忆,我们把总线基地址和外设基地址都以相应的宏定义起来,总线或者外设都以他们的名字作为宏名。

            首先定义了 “片上外设”基地址PERIPH_BASE,接着在PERIPH_BASE 上加入各个总线的地址偏移, 得到APB1 、APB2 总线的地址APB1PERIPH_BASE 、APB2PERIPH_BASE,在其之上加入外设地址的偏移,得到GPIOA-G的外设地址,最后在外设地址上加入各寄存器的地址偏移,得到特定寄存器的地址。一旦有了具体地址,就可以用指针读写。

            该代码使用 (unsigned int *) 把GPIOB_BSRR 宏的数值强制转换成了地址,然后再用“*”号做取指针操作,对该地址的赋值,从而实现了写寄存器的功能。同样,读寄存器也是用取指针操作,把寄存器中的数据取到变量里,从而获取STM32 外设的状态。

    3.2  封装总线和外设基地址

            用上面的方法去定义地址,还是稍显繁琐,例如GPIOA-GPIOE 都各有一组功能相同的寄存器,如GPIOA_ODR/GPIOB_ODR/GPIOC_ODR 等等,它们只是地址不一样,但却要为每个寄存器都定义它的地址。为了更方便地访问寄存器,我们引入C 语言中的结构体语法对寄存器进行封装。

            这段代码用typedef 关键字声明了名为GPIO_TypeDef 的结构体类型,结构体内有7 个成员变量,变量名正好对应寄存器的名字。C 语言的语法规定,结构体内变量的存储空间是连续的,其中32 位的变量占用4 个字节,16 位的变量占用2 个字节。

             也就是说,我们定义的这个GPIO_TypeDef ,假如这个结构体的首地址为0x40010C00(这也是第一个成员变量CRL 的地址), 那么结构体中第二个成员变量CRH 的地址即为0x4001 0C00 +0x04 ,加上的这个0x04 ,正是代表CRL 所占用的4 个字节地址的偏移量,其它成员变量相对于结构体首地址的偏移,在上述代码右侧注释已给。

             这样的地址偏移与STM32 GPIO 外设定义的寄存器地址偏移一一对应,只要给结构体设置好首地址,就能把结构体内成员的地址确定下来,然后就能以结构体的形式访问寄存器。

             这段代码先用GPIO_TypeDef 类型定义一个结构体指针GPIOx,并让指针指向地址GPIOB_BASE(0x4001 0C00),使用地址确定下来,然后根据C 语言访问结构体的语法,用GPIOx->ODR 及GPIOx->IDR 等方式读写寄存器。

            最后,我们更进一步,直接使用宏定义好GPIO_TypeDef 类型的指针,而且指针指向各个GPIO端口的首地址,使用时我们直接用该宏访问寄存器即可。

            这里我们仅是以GPIO 这个外设为例,给大家讲解了C 语言对寄存器的封装。以此类推,其他外设也同样可以用这种方法来封装。好消息是,这部分工作都由固件库帮我们完成了,这里我们只是分析了下这个封装的过程,让大家知其然,也只其所以然。

    4  总结与分析

            对于STM32而言,使用“GPIOA->ODR=0x00000000;”来对寄存器赋值的原理,也就是将GPIO下的所有寄存器放在一个结构体内,通过基地址和在基地址上的偏移地址不断转化,最终找到准确的寄存器实际地址来进行赋值。也就是说,和51单片机最大的不同就是:由于STM32的寄存器数目太多,就将其中控制同一外设的寄存器设置成一个结构体(如GPIO、DMA等),通过对结构体的地址和寄存器相对于结构体的偏移地址,来确定某个特定的寄存器。

    展开全文
  • 自然优先级INT0高TF0INT1TF1RI/TITF2/EXF2低定时器/计数器控制寄存器TCONTCON.7TCON.6TCON.5TCON.4TCON.3TCON.2TCON.1TCON.0TF1TR1TF0TR0IE1IT1IE0IT0Timer1中断标志CPU设置Timer1启动开关TR1=1;启动Timer1TR1=0;...

    自然优先级

    INT0

    TF0

    INT1

    TF1

    RI/TI

    TF2/EXF2

    定时器

    /

    计数器控制寄存器

    TCON

    TCON.7

    TCON.6

    TCON.5

    TCON.4

    TCON.3

    TCON.2

    TCON.1

    TCON.0

    TF1

    TR1

    TF0

    TR0

    IE1

    IT1

    IE0

    IT0

    Timer1

    断标志

    CPU

    设置

    Timer1

    动开关

    TR1=1

    ;启

    Timer1

    TR1=0

    ;关

    Timer1

    Timer0

    断标志

    CPU

    设置

    Timer0

    动开关

    TR0=1

    ;启

    Timer1

    TR0=0

    ;关

    Timer0

    INT1

    中断

    标志

    CPU

    设置

    INT1

    信号

    种类

    IT1=1

    ;负

    边沿触发

    IT1=0

    ;低

    电平触发

    INT0

    中断

    标志

    CPU

    设置

    INT0

    信号

    种类

    IT0=1

    ;负

    边沿触发

    IT0=0

    ;低

    电平触发

    定时器

    /

    计数器功能

    外部中断功能

    定时器

    /

    计数器方式寄存器

    TMOD

    Bit7

    Bit6

    Bit5

    Bit4

    Bit3

    Bit2

    Bit1

    Bit0

    GATE

    C/T

    M1

    M0

    GATE

    C/T

    M1

    M0

    Timer1

    Timer0

    GATE

    门控开关

    GATE=0

    ;设为内部启动,只要

    TRx=1

    即可启用

    Timerx

    GATE=1

    设为外部启动,

    需要

    TRx=1

    同时

    INTx

    引脚为高电平才可启用

    Timerx

    C/T

    定时器

    /

    数器切换开关

    C/T=0

    ;设定为内部定时器,记数内部系统时钟

    12

    分频的信号

    C/T=1

    ;设定为外部计数器,计数信号由

    T0/T1

    引脚输入

    M1

    M0

    定时器

    /

    计数器模式选择开关

    0

    0

    Mode 0

    :两个

    13

    位定时器

    /

    计数器

    0

    1

    Mode 1

    :两个

    16

    位定时器

    /

    计数器

    1

    0

    Mode 2

    :两个

    8

    位自动重装定时器

    /

    计数器

    1

    1

    Mode 3

    :一个

    8

    位定时器

    /

    计数器,一个

    8

    位定时器

    展开全文
  • I2C中24C02从地址设置 从设备地址 首先,先看一下AT24C02的芯片资料,我们会发现AT24C02有三个地址A0,A1,A2。同时,我们会在资料的Device Address介绍发现I2C器件一共有七位地址码,还有一位是读/写(R/W)操作位...

    I2C中24C02从地址设置

    设备地址

        首先,先看一下AT24C02的芯片资料,我们会发现AT24C02有三个地址A0,A1,A2。同时,我们会在资料的Device Address介绍发现I2C器件一共有七位地址码,还有一位是读/写(R/W)操作位,而在AT24C02的前四位已经固定为1010。R/W为1则为 读操作,为0则为写操作。R/W位我们要设置为0(写操作)

    规则为:1010(A0)(A1)(A2)(R/W)

        然后,看一下自己的设置PCB上的AT24C02的三位地址引脚的接法。

    例子1:

    那么对应的A0,A1,A2都是接的VCC,所以为A0=1,A1=1,A2=1;可以知道AT24C02的设备写地址为10101110(0xae),读设备地址为10101111(0xaf);

     

     

    例子2:

    那么对应的A0,A1,A2都是接的GND,所以为A0=0,A1=0,A2=0;可以知道AT24C02的设备写地址为10100000(0xa0),读设备地址为10100001(0xa1);

    哈哈,“设备地址”就这么确定了,其实也很简单。

     

    参考 http://blog.chinaunix.net/uid-29727172-id-5573269.html

    转载于:https://www.cnblogs.com/caolinsummer/p/5660863.html

     

    -------------------------------------------------------------------------------------------

    EEPROM应该是学习IIC总线时候最先接触的东西了,EEPROM的优点是可以随机存取,不像Flash存储器一样需要先擦除在能写入,而且擦写次数多存储时间长,但是缺点是存储空间非常有限,像我这用的Atmel的AT24C08只有8Kbit的存储空间,也就是只有1KB,存储一些参数是够的,但是存储文档、音频什么的就算了,还好我现在项目只要存储一些参数,AT24C02的空间不够,所以用了空间相对大一点的AT24C08。

    本以为两个的程序是差不多的,但是还有些值得注意的地方要记录一下的。


    由于AT24C02的存储空间是256Byte,IIC发送寻址地址的时候一个字节就够了,也就是发送完器件地址之后直接发送一个字节的寄存器地址就可以了,但是AT24C08的存储空间是1024Byte,一个字节的寄存器地址不够寻址,需要10位的寻址空间。

    我之前写过一篇文章:http://blog.csdn.net/tq384998430/article/details/53580267

    IIC读写16位地址的寄存器


    一般来说IIC器件的内部寄存器地址都是8位的,这样在进行读写操作时,发送完器件地址之后直接发送一个字节的寄存器地址,然后即可以进行读写。

    但是有的器件内部寄存器是按照16位地址编排的,例如一些EEPROM器件,由于存储的数据量较大就会需要较大的寻址空间,对于这种的器件的内部寄存器寻址就需要多个字节的地址,也就是在发送完器件地址之后需要发送多个寄存器地址字节,

    具体实现如下程序所示:

    u8 IIC_Read2(u8 device,u16 addr)
    {
        u8 temp;
        IIC_Start();
        IIC_SendByte(device);
        IIC_Wait_Ack();
        IIC_SendByte((u8)(addr >> 8));
        IIC_Wait_Ack();
        IIC_SendByte((u8)addr);
        IIC_Wait_Ack();
        IIC_Start();
        IIC_SendByte(device+1);
        IIC_Wait_Ack();
        temp = IIC_ReadByte();
        IIC_NAck();//发送nACK
        IIC_Stop();
        return temp;
    }
    通过程序可以看到发送完器件地址device之后先后发送了寄存器地址的高字节和低字节,然后再进行读取。
     

    里面说明了IIC读写16位地址的寄存器的方式,就是发送两个字节的寄存器地址,先发送地址的高字节,再发送地址的低字节,但是这一招在AT24C08上不适用,

    然后就逼我看一下AT24C08的数据手册http://pdf1.alldatasheet.com/datasheet-pdf/view/509421/ATMEL/AT24C08C-SSHM-T.html,上面第10页写道:


    Standard EEPROM Access: The 4K and 8K EEPROM device requires an 8-bit device address word following a start
    condition to enable the chip for a read or write operation. The device address word consists of a mandatory “1010” (0xA)
    sequence for the first four Most Significant Bits (MSB) as shown in Figure 8-1 on page 11. This is common to all the
    EEPROM devices.
    The 4K EEPROM only uses the A2 and A1 device address bits with the third bit being a memory page address bit. The
    two device address bits must compare to their corresponding hard-wired input pins. The A0 pin is no connect.
    The 8K EEPROM only uses the A2 device address bit with the next two bits being for memory page addressing. The A2
    address bit must compare to its corresponding hard-wired input pin. The A1 and A0 pins are no connect.


    AT24C08的器件地址的定义如下:

    这里写图片描述

    说得很清楚,AT24C08将器件地址(Device Addr)中的A1和A0位作为Page address,也就是说A1和A0是存储器的10位地址中的最高两位,我们再读写数据的时候要将地址的最高两位(page地址)放在这里。示例程序如下:

    void IIC_Send(u8 device,u16 addr,u8 dat)
    {
        IIC_Start();
        IIC_SendByte(device | (addr >> 8));
        IIC_Wait_Ack();
        IIC_SendByte((u8)addr);  
        IIC_Wait_Ack();  
        IIC_SendByte(dat);
        IIC_Wait_Ack();
        IIC_Stop();
    }
    ————————————————
    版权声明:本文为CSDN博主「Mr qqtang」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/tq384998430/article/details/79227271

    展开全文
  • C语言复习+寄存器地址名称映射一.参考资料探索者STM32F4开发板:**《STM32F4开发指南-库函数版本》4.1小节C语言基础知识复习4.6小节 MDK中寄存器地址名称映射**STM32F4xx官方资料:《STM32F4xx中文参考手册》-第7章...

    C语言复习+寄存器地址名称映射

    一.参考资料探索者STM32F4开发板:

    **《STM32F4开发指南-库函数版本》4.1小节C语言基础知识复习

    4.6小节 MDK中寄存器地址名称映射**

    STM32F4xx官方资料:

    《STM32F4xx中文参考手册》-第7章通用IO

    二.C语言复习位操作

    day8-1.pngGPIOA->ODR|=1<<5;

    TIMx->SR = (uint16_t)~TIM_FLAG;define宏定义关键词define是C语言中的预处理命令,它用于宏定义,可以提高源代码的可读性,为编程提供方便。

    常见的格式:

    #define 标识符 字符串

    “标识符”为所定义的宏名。“字符串”可以是常数、表达式、格式串等。

    例如:

    #define SYSCLK_FREQ_72MHz 72000000

    定义标识符SYSCLK_FREQ_72MHz的值为72000000。ifdef条件编译

    单片机程序开发过程中,经常会遇到一种情况,当满足某条件时对一组语句进行编译,而当条件不满足时则编译另一组语句。条件编译命令最常见的形式为:#ifdef 标识符

    程序段1

    #else

    程序段2

    #endif

    例如:#ifdef STM32F10X_HD

    大容量芯片需要的一些变量定义

    #endextern变量申明C语言中extern可以置于变量或者函数前,以表示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义。

    这里面要注意,对于extern申明变量可以多次,但定义只有一次。

    main.c文件:u8 id;//定义只允许一次

    main()

    {

    id=1;

    printf("d%",id);//id=1

    test();

    printf("d%",id);//id=2

    }

    test.c文件:extern u8 id;

    void test(void){

    id=2;

    }typedef类型别名

    定义一种类型的别名,而不只是简单的宏替换。可以用作同时声明指针型的多个对象。typedef unsigned char uint8_t;

    typedef unsigned short int uint16_t;

    typedef unsigned int uint32_t;

    typedef unsigned __int64 uint64_t;结构体Struct 结构体名{

    成员列表1;

    成员变量2;

    }变量名列表;

    在结构体申明的时候可以定义变量,也可以申明之后定义,方法是:

    Struct 结构体名字 结构体变量列表 ;结构体作用:同一个类型可以用数组,不同类型可以用结构体组织。

    结构体可扩展性强。

    举例说明:void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)static关键字Static申明的局部变量,存储在静态存储区。

    它在函数调用结束之后,不会被释放。它的值会一直保留下来。

    所以可以说static申明的局部变量,具有记忆功能。

    三.MDK中寄存器地址名称映射分析

    1.51中映射方法:sfr P0 =0x80;//P0映射到地址0x80

    P0=0x00//忘寄存器地址0x80赋值0x00

    2.STM32中操作:GPIOA->ODR=0x00000000;值0x00000000是怎么赋值给了GPIOA的ODR寄存器地址的呢?

    也就是说GPIOA->ODR这种写法,是怎么与GPIOA的ODR寄存器地址映射起来的?

    day8-2.png

    day8-3.png

    展开全文
  • 西门子PLC基于MODBUS RTU通信协议时的寄存器地址对应关系及错误代码 西门子PLC在使用MODBUS RTU通信协议时,寄存器的地址是如何对应的?为什么第一个寄存器地址是40001? 功能码对照表如下:(H为16进制) 由上面...
  • 要操作寄存器,实际是操作对应地址的数据。如GPIOA->ODR = 0,将GPIOA的所有端口输出置位0. 那在CMSIS(cortex microcontroller software interface standard)中是如何实现的? 首先将GPIO相关的寄存器定义为一个...
  • android高通i2c/cci控制没有寄存器地址的马达/设备
  • 我需要编写一个I2C程序,该程序可以使用I2C_RDWR ioctl将数据写入32位和16位寄存器地址。据我所知,设备地址和数据使用linux i2c驱动程序中定义的结构i2c_msg中的相同缓冲区buf一起传递到设备中:struct i2c_msg {__...
  • 16位I2C寄存器地址读写接口 I2C读写接口 static int max96722_read_reg(struct i2c_client *client, unsigned char reg_addr, unsigned char *buf, unsigned char len) { int ret; int retry = I2C_BUS_READ_WRITE_...
  • 图2. 带有寄存器地址(I2...将16为变址寄存器地址置于数据的前2个字节,使字节的数量等于发送数据的原始数量加2.UART/I2C转换器将去掉标准写数据包中的8位寄存器地址,如图1所示。例如,如果外设需要16位变址寄存...
  • //说明:当线路控制寄存器(LCR)的bit7=0 : DLAB=0,允许访问接收/发送及中断允许寄存器 // 当线路控制寄存器(LCR)的bit7=1 : DLAB=1,允许访问波特率因子寄存器 //-------------------------------------...
  • 为什么stm32的相邻寄存器地址相差0x04? stm32中有一个很大的空间,被划分为几个区域。在划分区域之前,已经认为的为这个大空间编好了地址,以一个字节(8位)为最小单位进行地址编排。其中一个区用来编排外设的地址...
  • 地址我们是不知道的,读那个寄存器也是不清楚的,我只知道0x00是X轴的数据,0x01是Y轴0x02是Z轴。 那就试出来: 比如说,我们需要在 a 地址的IIC器件的 b 寄存器写一个数据 c ,以启动这个器件。或者完成他的...
  • CK-FR12-AB工业RFID读写器部分元件内置ESD保护电路,但当模块的恶劣的环境中使用时,依然建议用户在...本文将重点介绍CK-FR12-AB工业RFID读写器的寄存器地址内存分配与数据读、写流程,让自动化工控人快速上手此设备。
  • 读芯片的寄存器定义文档的时候,每个寄存器都定义了各自的地址。这个地址看起来和内存的地址是一样一样的。那中间有什么关联呢?其实没啥大的关联,只不过寄存器地址和内存的地址都是在CPU的寻址空间中。简单的说...
  • 首先要清楚的一点, 所有操作, 最终目的都是操作寄存器 一,对比51单片机和STM32对寄存器的操作 ...ODR=0x00000000 //为GPIOA的ODR寄存器地址赋值0x00000000 二,以GPIOA为例说明STM32寄存器和名称的映
  • AX BX CX DX是CPU内部的四个16bit的通用寄存器,常用于存储数据,也叫数据寄存器,一般用于存放参与运算的数据或运算的结果。 为了兼容更古老的CPU,他们的16bit可以分为高八位和第八位,如AH,AL。这种灵活的使用...
  • 在Modbus实际应用中,我们对Modbus 3区、4区的地址有的时候会...从上面的定义可以看出来,3区,4区的寄存器开始地址不是0,而是30001和40001,但是在modbus协议中,这两区的起始地址却是可以从0开始的,那么这是为什
  • 【汇编语言】寄存器地址

    千次阅读 多人点赞 2021-03-04 18:40:57
    寄存器地址 主要内容: 一、寄存器 (1)透明寄存器 (2)可编程寄存器 1.通用寄存器 2.专用寄存器 二、地址 (1)存储模型 (2)存储空间分段管理 (3)物理地址与逻辑地址 (4)操作数寻址过程
  • 寄存器地址名称映射 写在前面: 对于MCU,一切低层配置都是配置寄存器 51中的映射方法: sfr P0=0x08;//P0映射到地址0x08 P0=0x00//往寄存器地址0x08赋值0x00 STM32中的操作: GPIOA->ODR=0x00000000; ...
  • i2c-tools工具是一个专门调试i2c的,开源,可获取挂载的设备及设备地址,还可以在对应的设备指定寄存器设置值或者获取值等功能。 一、下载i2c-tools,交叉编译 1、从开源网站...
  • 树莓派4B 寄存器地址查询

    千次阅读 2020-12-27 00:03:42
    树莓派4B 寄存器地址查询 树莓派4B的datasheet在我看来非常混乱复杂,尤其是地址映射方面。单datasheet就有两个版本而且还自相矛盾。为了查找到确定的物理地址,使用官方提供的函数进行读取。 首先在应用层插入...
  • SPI的状态寄存器的偏移地址是0x04,复位地址是0x00 这个偏移地址0x04是什么意思???????
  • 一、STM32F103系列芯片的地址映射和寄存器映射原理 1.什么是寄存器? (1)基本含义 寄存器是CPU内部用来存放数据的一些小型存储区域,用来暂时存放参与运算的数据和运算结果。其实寄存器就是一种常用的时序逻辑电路...
  • STM32 对外设基地址,总线外设基地址寄存器地址的理解 前言 本博文基于STM32F103ZET6和MDK以及V3.5.0库函数; 本博文从Cortex-M3内核的寻址空间映射一直聊到库函数是怎样配置具体的某一个寄存器; 如有...
  • 通用寄存器

    2021-07-28 06:43:31
    通用寄存器可用于传送和暂存数据,也可参与算术逻辑运算,并保存运算结果。除此之外,它们还各自具有一些特殊功能。汇编语言程序员必须熟悉每个寄存器的一般用途和特殊用途,只有这样,才能在程序中做到正确、合理地...
  • 0x2进制 1x8进制 3x10进制 4x代表16进制 比如累计热量 寄存器地址就是2 累计流量寄存器地址就是6
  • 1 寄存器地址的定义:#define UART_BASE_ADRS (0x10000000) /* 串口的基地址 */#define UART_RHR *(volatile unsigned char *)(UART_BASE_ADRS + 0) /* 数据接受寄存器 */#define UART_THR *(volatile unsigned char...
  • 一、杂谈寄存器

    2021-03-31 01:30:58
    2:寄存器地址 3:寄存器与结构体 4:寄存器调试 总结: 1:寄存器 在写程序中最开始的代码时是“Hello world!”,而单片我们最常做的, 点亮LED。在下面C51程序的功能是点亮LED0。 #include "reg52.h" ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 334,588
精华内容 133,835
关键字:

寄存器地址

友情链接: avr_lib_wiinunchuck_02.zip