STM32处理器寄存器配置。
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了STM32处理器寄存器配置。相关的知识,希望对你有一定的参考价值。
问题一:端口低配置寄存器CRL的复位值是0X4444 4444,请问怎样去理解呢,我是这样理解的,(4444 4444)=(0100 0100 0100 0100 0100 0100 0100 0100)可是看书中标示的也没能看出来啊?
问题二:CNF7[1:0] MODE7[1:0],这是什么意思啊?他们各占几个位?(书上说的是CNF两个位,MODE两个位,可是我还是理解不了)。
问题三:设置PORTC的1位为上拉输入,12位为推挽输出,代码如下:
GPIOC->CRH&=0XFFF00FFF;
GPIOC->CRH|=0X00038000;
GPIOC->ODR=1<<11;
请问“->”是什么意思?好像不是运算符吧,第三条语句“1<<11”是什么意思,11怎么来的?
问题四:位31:30,这标示的是什么意思啊?
我觉的要是在这之前学习一下AVR可能会好理解。
我买了一本《例说STM32》感觉不错,不过我的板子跟书不配套,我觉得没必要再买一块儿了。
我之前学习都是调用库函数来写程序的,看了看这本书才知道怎样操作寄存器。求帮助。
谢谢你们,回答的都不错!
一、端口配置寄存器是用于配置GPIO工作模式的,具体各位的意义要看手册:
二、CN7[1:0] 是指CN7配置占两位,分别对应自己所在位的高位(1)、低位(0),手册中如此标识也是为了便于说明。如果占用3位,可标识为xxx[2:0],以下说明时可表示bit2,bit1,bit0;其他同理。
三、->是结构体指针引用结构成员符号,GPIOC本质上是结构体指针,结构体:
typedef struct
vu32 CRL;
vu32 CRH;
vu32 IDR;
vu32 ODR;
vu32 BSRR;
vu32 BRR;
vu32 LCKR;
GPIO_TypeDef;
1<<11,是移位操作,即1向左移11位,这个11是根据所要设置寄存器的位置来确定的,具体的可以查看手册。明白这个意思,可以举一反三。
四、位31:30 就是指在整个32位寄存器中,所占位置为 31位和30位。注意,一般位标识是从0开始的,所以32位寄存器表示位31到位0.
参考技术A RCC->CR=0x10000;//使能外部高速时钟 8Mhz RCC->CFGR=0x1;//使用至于三个寄存器的设置,可以参考附件,通过keil的配置模板进行。具体的程序,UpDqrRSTM32:GPIO口的使用
1 GPIO port
STM32一共有7组GPIO port,分别是GPIOA[15:0]~GPIOG[15:0],每组GPIO port 有16个 pin;每组GPIO port都有一组寄存器;
GPIO寄存器的控制单位是GPIO port,而不是pin;所以寄存器的最小处理单位是一个16位的字长(0xFF);
至于寄存器的配置我们之后小节在解析,首先来了解一下标准库是如何将GPIO映射到地址上的;
/*stm32f10x.h 1408-1414行声明如下*/ #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-1010行; *把结构体的首地址映射到GPIO的首寄存器地址,就可以通过该结构体对硬件寄存器操作; *结构体的地址通过结构体指针来赋值对应上*/ #define __IO volatile /*core_cm3.h NO.116*/ 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; /*stm32f10x.h 1315-1321;*/ #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 1282-1283; GPIO都属于APB2总线,使用的时候要使能APB2总线的时钟源;*/ #define APB1PERIPH_BASE PERIPH_BASE #define APB2PERIPH_BASE (PERIPH_BASE + 0x10000) /*stm32f10x.h 1274*/ #define PERIPH_BASE ((uint32_t)0x40000000)
2 GPIO 寄存器
GPIO涉及的寄存器较多,复用功能和重映射功能都需要配置专门的AFIO寄存器,但是本节暂时没有涉及;
本节主要介绍了通用GPIO口涉及到的7个寄存器,具体寄存器的说明和使用如下;
2.1 CRL端口配置低寄存器,CRH端口配置高寄存器 control register low,control register high;
CRL和CRH都是32位寄存器,如下图所示,一起用来控制该组GPIO port的16个引脚配置;
2.1.1 寄存器复位值为0x4444_4444;CRL偏移地址:0x00,CRH偏移地址:0x04;配置信息封装如下;
//定义了CRH和CRL寄存器需要的参数;以下声明在stm32f10x_gpio.h的前200行; typedef struct { uint16_t GPIO_Pin; /*用16位bit的每一位分别表示一个引脚*/ GPIOSpeed_TypeDef GPIO_Speed; /*用2位bit来表示输出模式的最大速度*/ GPIOMode_TypeDef GPIO_Mode; /*CNF MODE,具体见结构体*/ }GPIO_InitTypeDef; #define GPIO_Pin_0 ((uint16_t)0x0001) /*0000 0000 0000 0001b*/ #define GPIO_Pin_1 ((uint16_t)0x0002) /*0000 0000 0000 0010b*/ #define GPIO_Pin_2 ((uint16_t)0x0004) /*0000 0000 0000 0100b*/ #define GPIO_Pin_3 ((uint16_t)0x0008) /*0000 0000 0000 1000b*/ #define GPIO_Pin_4 ((uint16_t)0x0010) /*0000 0000 0001 0000b*/ #define GPIO_Pin_5 ((uint16_t)0x0020) /*0000 0000 0010 0000b*/ #define GPIO_Pin_6 ((uint16_t)0x0040) /*0000 0000 0100 0000b*/ #define GPIO_Pin_7 ((uint16_t)0x0080) /*0000 0000 1000 0000b*/ #define GPIO_Pin_8 ((uint16_t)0x0100) /*0000 0001 0000 0000b*/ #define GPIO_Pin_9 ((uint16_t)0x0200) /*!< Pin 9 selected */ #define GPIO_Pin_10 ((uint16_t)0x0400) /*!< Pin 10 selected */ #define GPIO_Pin_11 ((uint16_t)0x0800) /*!< Pin 11 selected */ #define GPIO_Pin_12 ((uint16_t)0x1000) /*!< Pin 12 selected */ #define GPIO_Pin_13 ((uint16_t)0x2000) /*!< Pin 13 selected */ #define GPIO_Pin_14 ((uint16_t)0x4000) /*!< Pin 14 selected */ #define GPIO_Pin_15 ((uint16_t)0x8000) /*!< Pin 15 selected */ #define GPIO_Pin_All ((uint16_t)0xFFFF) /*!< All pins selected */ #define IS_GPIO_PIN(PIN) ((((PIN) & (uint16_t)0x00) == 0x00) && ((PIN) != (uint16_t)0x00)) typedef enum { GPIO_Speed_10MHz = 1, /*output MODE[1:0]*/ GPIO_Speed_2MHz, /*output MODE[1:0]*/ GPIO_Speed_50MHz /*output MODE[1:0]*/ }GPIOSpeed_TypeDef; #define IS_GPIO_SPEED(SPEED) (((SPEED) == GPIO_Speed_10MHz) || ((SPEED) == GPIO_Speed_2MHz) || ((SPEED) == GPIO_Speed_50MHz)) typedef enum { GPIO_Mode_AIN = 0x0, /*0000 0000b input [3:0]CNF+MODE*/ GPIO_Mode_IN_FLOATING = 0x04, /*0000 0100b input [3:0]CNF+MODE*/ GPIO_Mode_IPD = 0x28, /*0010 1000b input [6]下拉,[3:0]CNF+MODE*/ GPIO_Mode_IPU = 0x48, /*0100 1000b input [7]上拉,[3:0]CNF+MODE*/ GPIO_Mode_Out_OD = 0x14, /*0001 0100b [5]output,[3:2]CNF*/ GPIO_Mode_Out_PP = 0x10, /*0001 0000b [5]output,[3:2]CNF*/ GPIO_Mode_AF_OD = 0x1C, /*0001 1100b [5]output,[3:2]CNF*/ GPIO_Mode_AF_PP = 0x18 /*0001 1000b [5]output,[3:2]CNF*/ }GPIOMode_TypeDef; #define IS_GPIO_MODE(MODE) (((MODE) == GPIO_Mode_AIN) || ((MODE) == GPIO_Mode_IN_FLOATING) || ((MODE) == GPIO_Mode_IPD) || ((MODE) == GPIO_Mode_IPU) || ((MODE) == GPIO_Mode_Out_OD) || ((MODE) == GPIO_Mode_Out_PP) || ((MODE) == GPIO_Mode_AF_OD) || ((MODE) == GPIO_Mode_AF_PP)) #define IS_GET_GPIO_PIN(PIN) (((PIN) == GPIO_Pin_0) || ((PIN) == GPIO_Pin_1) ||((PIN) == GPIO_Pin_2) || ((PIN) == GPIO_Pin_3) || ((PIN) == GPIO_Pin_4) || ((PIN) == GPIO_Pin_5) || ((PIN) == GPIO_Pin_6) || ((PIN) == GPIO_Pin_7) || ((PIN) == GPIO_Pin_8) || ((PIN) == GPIO_Pin_9) || ((PIN) == GPIO_Pin_10) || ((PIN) == GPIO_Pin_11) || ((PIN) == GPIO_Pin_12) ||((PIN) == GPIO_Pin_13) || ((PIN) == GPIO_Pin_14) || ((PIN) == GPIO_Pin_15)) typedef enum { Bit_RESET = 0, Bit_SET }BitAction;
2.1.2 配置CRL和CRH的初始化代码如下;
/*以下代码位于stm32f10x_gpio.c中,配置相应port的CRL和CRH*/ void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct) { uint32_t currentmode = 0x00, currentpin = 0x00, pinpos = 0x00, pos = 0x00; uint32_t tmpreg = 0x00, pinmask = 0x00; assert_param(IS_GPIO_ALL_PERIPH(GPIOx)); assert_param(IS_GPIO_MODE(GPIO_InitStruct->GPIO_Mode)); assert_param(IS_GPIO_PIN(GPIO_InitStruct->GPIO_Pin)); currentmode = ((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x0F); //currentmode保留了GPIO_Mode[3:0]; if ((((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x10)) != 0x00)//如果GPIO_Mode[4]为1,表示为输出模式; { /*if(输出模式),将CNF[1:0]和MODE[1:0]的信息保存到currentmode[3:0]*/ assert_param(IS_GPIO_SPEED(GPIO_InitStruct->GPIO_Speed)); currentmode |= (uint32_t)GPIO_InitStruct->GPIO_Speed;//currentmode或上GPIO_Speed[1:0]; } /*以下部分为CRL Configuration*/ if (((uint32_t)GPIO_InitStruct->GPIO_Pin & ((uint32_t)0x00FF)) != 0x00) //if(是低8位pin); { tmpreg = GPIOx->CRL; //temreg存放CRL寄存器的信息; for (pinpos = 0x00; pinpos < 0x08; pinpos++) //pinpos为几,表示引脚几; { pos = ((uint32_t)0x01) << pinpos; currentpin = (GPIO_InitStruct->GPIO_Pin) & pos; //currentpin:要么为当前pin值,要么为0; if (currentpin == pos) { pos = pinpos << 2; //pos:引脚对应的CRL配置位 pinmask = ((uint32_t)0x0F) << pos; //pinmask:引脚对应的CRL[3:0]置1 tmpreg &= ~pinmask; //temreg中对应引脚的[3:0]清0 tmpreg |= (currentmode << pos); //temreg中对应引脚的[3:0]配置成currentmode[3:0] //此处的if else应该是通过ODR来配置硬件,由中文参考手册8.1.7原理图推测可知 if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD) //if(输入连下拉电阻) { GPIOx->BRR = (((uint32_t)0x01) << pinpos); //通过配置ODR的16bit,对应pin的bit置0,连接下拉电阻; } else { if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)//if(输入连上拉电阻) { GPIOx->BSRR = (((uint32_t)0x01) << pinpos); //通过配置ODR的16bit,对应pin的bit置1,连接上拉电阻; } } } } GPIOx->CRL = tmpreg; //把配置好对应pin脚的temreg放回CRL中 } /*---------------------------- GPIO CRH Configuration ------------------------*/ /* Configure the eight high port pins */ if (GPIO_InitStruct->GPIO_Pin > 0x00FF) { tmpreg = GPIOx->CRH; for (pinpos = 0x00; pinpos < 0x08; pinpos++) { pos = (((uint32_t)0x01) << (pinpos + 0x08)); /* Get the port pins position */ currentpin = ((GPIO_InitStruct->GPIO_Pin) & pos); if (currentpin == pos) { pos = pinpos << 2; /* Clear the corresponding high control register bits */ pinmask = ((uint32_t)0x0F) << pos; tmpreg &= ~pinmask; /* Write the mode configuration in the corresponding bits */ tmpreg |= (currentmode << pos); /* Reset the corresponding ODR bit */ if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD) { GPIOx->BRR = (((uint32_t)0x01) << (pinpos + 0x08)); } /* Set the corresponding ODR bit */ if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU) { GPIOx->BSRR = (((uint32_t)0x01) << (pinpos + 0x08)); } } } GPIOx->CRH = tmpreg; } }
2.2 LCKR端口配置锁定寄存器:lock register
复位值为0x0000_0000;偏移地址:0x18;
用来锁存对应端口的CRL,CRH寄存器的配置;修改完LCK[15:0]然后锁定[LCKK],对应的CRL,CRH配置将会持续到下次系统复位信号来临;
2.3 IDR端口输入数据寄存器,ODR端口输出数据寄存器:input data register,output data register;
复位值为0x0000_0000;IDR偏移地址:0x08;ODR偏移地址:0x0C
对于输入数据而言,每个APB2时钟会采样I/O脚上的数据存入数据寄存器中,对寄存器的读取可以获得输入数据;
对于输出数据而言,应该也是通过APB2时钟控制,把数据放入ODR即可;
2.3.1 IDR寄存器的使用函数
/*以下代码位于stm32f10x_gpio.c中
*1 读取IDR寄存器某一位的值,即pin值;
*2 读取IDR寄存器的值,即port值;
*/ uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) { uint8_t bitstatus = 0x00; /* Check the parameters */ assert_param(IS_GPIO_ALL_PERIPH(GPIOx)); assert_param(IS_GET_GPIO_PIN(GPIO_Pin)); /*先读取整个IDR寄存器,然后通过&来读取bit,IDR寄存器的最小处理单位是16bit*/ if ((GPIOx->IDR & GPIO_Pin) != (uint32_t)Bit_RESET) { bitstatus = (uint8_t)Bit_SET; } else { bitstatus = (uint8_t)Bit_RESET; } return bitstatus; } uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx) { /* Check the parameters */ assert_param(IS_GPIO_ALL_PERIPH(GPIOx)); return ((uint16_t)GPIOx->IDR); }
2.3.2 ODR寄存器的使用函数
/*以下代码位于stm32f10x_gpio.c中; *1 读取ODR寄存器某一位的值;即读取pin值; *2 读取ODR寄存器的值;即读取port值; *3 向ODR寄存器写入port值;
*/ uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) { uint8_t bitstatus = 0x00; assert_param(IS_GPIO_ALL_PERIPH(GPIOx)); assert_param(IS_GET_GPIO_PIN(GPIO_Pin)); /*先读取整个ODR寄存器,然后通过&来读取bit,ODR寄存器的最小处理单位是16bit*/ if ((GPIOx->ODR & GPIO_Pin) != (uint32_t)Bit_RESET){ bitstatus = (uint8_t)Bit_SET; } else{ bitstatus = (uint8_t)Bit_RESET; } return bitstatus; } uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx) { assert_param(IS_GPIO_ALL_PERIPH(GPIOx)); return ((uint16_t)GPIOx->ODR); } void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal) { assert_param(IS_GPIO_ALL_PERIPH(GPIOx)); GPIOx->ODR = PortVal; }
2.4 BSRR端口置位/复位寄存器,BRR端口复位寄存器:bit set/reset register,bit reset register;
复位值为0x0000_0000;BSRR偏移地址:0x10;BRR偏移地址:0x14;
对BSRR,BRR的操作,就是对该组GPIO口的ODR寄存器寄存器的操作;
2.4.1 BSRR寄存器:pin置1
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) { assert_param(IS_GPIO_ALL_PERIPH(GPIOx)); assert_param(IS_GPIO_PIN(GPIO_Pin)); GPIOx->BSRR = GPIO_Pin; }
2.4.2 BRR寄存器:pin清0
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) { assert_param(IS_GPIO_ALL_PERIPH(GPIOx)); assert_param(IS_GPIO_PIN(GPIO_Pin)); GPIOx->BRR = GPIO_Pin; }
2.4.3 设置pin脚相应的数值:pin的置1清0
void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal) { assert_param(IS_GPIO_ALL_PERIPH(GPIOx)); assert_param(IS_GET_GPIO_PIN(GPIO_Pin)); assert_param(IS_GPIO_BIT_ACTION(BitVal)); if (BitVal != Bit_RESET) { GPIOx->BSRR = GPIO_Pin; } else { GPIOx->BRR = GPIO_Pin; } }
虽然BSRR和BRR都可以用来设置单独bit位,但是它们也是通过16bit长度来设置的,不要被函数具有迷惑性的名字给欺骗;
3 GPIO的复用和重映射寄存器
关于GPIO的复用重映射应该要加到上面寄存器的小节中,只是复用重映射似乎内容似乎有点多,可以另开一小节;
具体GPIO的复用重映射,有点懒,感觉补充起来也要一些时间,浏览了一下<STM32F10xxx中文参考手册>,具体内容在8.3和8.4小节;
GPIO口的重映射和复用功能是通过AFIO寄存器配置的;先占个坑,有缘在补充把;
3.1 另外标准库还为GPIO口提供了位带操作,大概就是有两个区域地址块的寄存器是可以直接以bit为单位进行设置;
相当于给GPIO开了个小灶方便某些不想使用标准库的人可以直接设置寄存器,个人不太中意这个功能;
4 通用GPIO的示例代码
配置GPIO端口,在寄存器层面来说:首先使能所在外设的时钟源,然后配置完CRL和CRH后GPIO口就可以使用了;
如果GPIO pin 配置成了输入引脚,则从IDR读取数据即可;
如果GPIO pin 配置成了输出引脚,输出的信号可以直接写入ODR寄存器,也可以通过BSRR和BRR来设置;
#include "delay.h" int main(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitTypeDef GPIO_Struct; //portA pin1 as input; GPIO_Struct.GPIO_Pin = GPIO_Pin_1; GPIO_Struct.GPIO_Mode =GPIO_Mode_IPD ; GPIO_Init(GPIOA, &GPIO_Struct); //portA pin2 as output; GPIO_Struct.GPIO_Pin = GPIO_Pin_2; GPIO_Struct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Struct.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOA, &GPIO_Struct); while(1) { GPIO_SetBits(GPIOA,GPIO_Pin_2); delay_ms(100); GPIO_ResetBits(GPIOA,GPIO_Pin_2); delay_ms(100); } }
5 小结
本文主要是结合通用GPIO口的寄存器,对标准库中通用GPIO口的代码进行了分析和概括;
然后提供了一个代码示例;如果只是使用而不想理解标准库原理,则直接使用接口函数即可,如代码示例所示;
以上是关于STM32处理器寄存器配置。的主要内容,如果未能解决你的问题,请参考以下文章