如下图是SOP8封装引脚示意图
这里将物理6号管脚上的NRST功能废止,将6号管脚当作PA2端口来使用。
想法参考博客园的这篇文章
正如博客园上的那篇文章所言:单片机默认开启了RESTSET功能,不受PIN模式的影响,所以你无论把它设置成INPUT、OUTPUT还是ANALOG,RESET永远生效,和这个PIN同处于同一个物理管脚的PIN就没法正常使用
要禁用RESET功能,要在芯片的OB(Option Bytes)里修改,在Puya第四版手册的第22页标注了OB的位置:0x1FFF 0E80
博客园的那篇文章说:对于正常带 PF4/BOOT0 的型号, 在上电时拉高 BOOT0, 就可以从 system memory 启动 boot loader, 通过 ISP 工具连接后在工具里修改 OB, 但是 SOP8 和 SOP16 这些封装没有 BOOT0, 所以没法使用 ISP 工具修改. 只能通过代码或第三方工具(例如JLink)修改.
所以他以LL库为例,说明了在代码中修改OB,以关闭RESET的方法。
我的创新点在于我以HAL库为例,说明在代码中修改OB,以关闭RESET的方法:
/**
* @brief 用于将SOP8封装的物理第6号引脚配置为PA2引脚
*/
static void APP_FlashSetOptionByte(void) {
FLASH_OBProgramInitTypeDef OBInitCfg;
//解锁FLASH
HAL_FLASH_Unlock();
//解锁OB
HAL_FLASH_OB_Unlock();
OBInitCfg.OptionType = OPTIONBYTE_USER;
OBInitCfg.USERType = OB_USER_BOR_EN | OB_USER_BOR_LEV | OB_USER_IWDG_SW | OB_USER_NRST_MODE | OB_USER_nBOOT1;
/*
* 默认的值: OB_BOR_DISABLE | OB_BOR_LEVEL_3p1_3p2 | OB_IWDG_SW | OB_WWDG_SW | OB_RESET_MODE_RESET | OB_BOOT1_SYSTEM;
*/
OBInitCfg.USERConfig = OB_BOR_DISABLE | OB_BOR_LEVEL_3p1_3p2 | OB_IWDG_SW | OB_RESET_MODE_GPIO | OB_BOOT1_SYSTEM;
HAL_FLASH_OBProgram(&OBInitCfg);
//锁定FLASH
HAL_FLASH_Lock();
//锁定OB
HAL_FLASH_OB_Lock();
//重新载入OB,这会触发软复位,重启MCU
HAL_FLASH_OB_Launch();
}
注意:在调用该函数时,需要做一个判断,否则单片机会一直循环重启
/* 调用修改OB函数,将SOP8封装的物理6号管脚的NRST功能废掉 */
if(READ_BIT(FLASH->OPTR,FLASH_OPTR_NRST_MODE) == OB_RESET_MODE_RESET) {
//在没有关闭NRST功能的情况下,调用下面的函数关闭
APP_FlashSetOptionByte();
}
到这里就关闭了SOP封装物理6号管脚的RESET功能,接下来我们初始化PA2引脚即可
/**
* @brief 引脚 PA2 初始化
*/
void PA2_GPIO_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_2,GPIO_PIN_RESET);
GPIO_InitStruct.Pin = GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA,&GPIO_InitStruct);
}
然后测试:
while (1) {
HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_2);
HAL_Delay(20);
}
下载代码后,PA2引脚应该会输出周期为40ms的方波
通过示波器测量PA2引脚:
可以看到确实输出了周期约为40ms的方波
证明我们之前的操作是正确且有效的。