||
昨天在想熟悉一下TFT的操作,发现其中提到对I/O口的位带操作,我小试牛刀,发现其中对I/O口的配置不是很清楚,所以我进一步了解了一下一般情况下用固件库函数对I/O口模式的设置,方便其和I/O位带操作进行一个比较。
以下是整个部分,我对其中的注释翻译过来并加入了自己的了解,用到的资料为:
(文中称资料A)STM32F10xx固件函数库(2.1.0版本)
(文中称资料B)STM32F10x微控制器参考手册(2009年12月第10版) 、
(文中称资料C)Cortex-M3权威指南CnR2(电子书)
方便大家查找 。
对GPIO_Init的设置其实主要是对CRL /CRH/BRR/ODR/ 这几个寄存器的设置。设置过程:
1、对输入的参数GPIO_InitStruct的引脚还原
2、对对应位引脚设置,分为设置模式,设置频率
每个引脚设置CNF[1:0],MODE[1:0]四位
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
//调用初始化函数要求输入参量GPIO口地址指针及结构体GPIO的地址指针
{
uint32_t currentmode = 0x00, currentpin = 0x00, pinpos = 0x00, pos = 0x00;
uint32_t tmpreg = 0x00, pinmask = 0x00;
/* Check the parameters 下面是检查是否超出该值取值范围,参见资料A P36 */
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));
/*---------------------------- GPIO Mode Configuration 模式配置-----------------------*/
/* 下面是所有模式的设定值
typedef enum
{
GPIO_Mode_AIN = 0x0,
GPIO_Mode_IN_FLOATING = 0x04,
GPIO_Mode_IPD = 0x28,
GPIO_Mode_IPU = 0x48,
GPIO_Mode_Out_OD = 0x14, //讲解为什么输出模式中几个值这么设定0x1-表示为输入
GPIO_Mode_Out_PP = 0x10, //展开4个位分别为:00010000 B --->0x10 后4位的第1、2位表示模式,最后两位表示频率,
GPIO_Mode_AF_OD = 0x1C, // 00010100B --->0x14 这里最后两位全部为0表示保留。
GPIO_Mode_AF_PP = 0x18 // 00011000B --->0x18 参见资料B P106 表17
}GPIOMode_TypeDef; // 00011100B --->0x1C
*/
currentmode = ((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x0F);
//当我们调用GPIO_Init的时候引入参量GPIO_InitStruct,其中GPIO_InitStruct->Mode
//中的模式为上面GPIOMode_TypeDef中的一种,和0x0F相与表示取相应模式的值
if ((((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x10)) != 0x00)
// 计算结果:若为0x0- ,则和(uint32_t)0x10相与后为0,对应的为输入
// 若为0x2/4/1-,当和(uint32_t)0x10相与后不为0对应为输出
// 若为输出模式进行下面的设置,为currentmode加上频率
{
/* Check the parameters 同上,检查是否超出设定值范围*/
assert_param(IS_GPIO_SPEED(GPIO_InitStruct->GPIO_Speed));
/* Output mode 输出模式*/
/* 速度有3种模式,依次为1、2、3 ---0x…01,0x…02,0x…03
typedef enum
{
GPIO_Speed_10MHz = 1,
GPIO_Speed_2MHz,
GPIO_Speed_50MHz
}GPIOSpeed_TypeDef;
*/
currentmode |= (uint32_t)GPIO_InitStruct->GPIO_Speed;
//对应输出模式加上输出频率值,一会用于写入控制寄存器(CR-)中
}
/*---------------------------- GPIO CRL Configuration 对CRL的配置------------------------*/
/* Configure the eight low port pins 配置低8位 */
//在main函数中有:
// GPIO_InitStructure.GPIO_Pin = GPIO_Pin_x | GPIO_Pin_x | GPIO_Pin_x | GPIO_Pin_x ;
// 如:
//GPIO_Pin_8 = 0x0100 GPIO_Pin_8 = 0x0200
// GPIO_Pin_8 = 0x0400 GPIO_Pin_8 = 0x0800
//当它们相或得0x0F00
if (((uint32_t)GPIO_InitStruct->GPIO_Pin & ((uint32_t)0x00FF)) != 0x00)
//分析上面的过程可得下面的if语句是否执行,若跳过不执行转到高8位执行即对CRH设置
//若满足则执行下面语句
{
tmpreg = GPIOx->CRL;
//暂存CRL的值到tmpreg
for (pinpos = 0x00; pinpos < 0x08; pinpos++) //position 0~7位配置
{
pos = ((uint32_t)0x01) << pinpos; //地址位左移相应pinpos位数,用于取得需要设置的对应位
/* Get the port pins position 取得端口脚的位置*/
currentpin = (GPIO_InitStruct->GPIO_Pin) & pos;//0x01由上面左移相应位得到pos
//刚刚在选取引脚的时候不是用了一个或选取引脚吗
//就是 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_x | GPIO_Pin_x |
// 然后把它与pos相与还原对应位分别得到低端的0~7位
if (currentpin == pos) //判断上面被还原位是否被选中,原理是当该位选中时条件就成立,否则currentpin值为0条件不会为真
{
//以下是设置pinpos对应位的模式,如pinpos是0x00,则表示对第零位设置
pos = pinpos << 2; // pinpos左移2位表示对CNF[1:0]设置,参见资料B P113
/* Clear the corresponding low control register bits 清除CRL中对应位*/
pinmask = ((uint32_t)0x0F) << pos;
tmpreg &= ~pinmask; //tmpreg暂存CRL的值,pinmask取反并与CRL值相与表示
//屏蔽对应位的值,达到清除对应位
/* Write the mode configuration in the corresponding bits 写入当前位的模式值*/
tmpreg |= (currentmode << pos); //写入对应位的模式设置,current表示当前的意思,在前面对模式的值有了一个提取,保存在currentmode中
//当前模式值左移到对应位后写入寄存器暂存
/* Reset the corresponding ODR bit */
if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)
{
GPIOx->BRR = (((uint32_t)0x01) << pinpos);
}
else
{
/* Set the corresponding ODR bit */
if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)
{
GPIOx->BSRR = (((uint32_t)0x01) << pinpos);
}
}
}
}
GPIOx->CRL = tmpreg; //最后8位都配置完成后写入CRL中
}
/*---------------------------- GPIO CRH Configuration ------------------------*/
//对CRH的设置,和CRL的配置一个原理
/* 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;
}
}