STM32单片机的调试接口一般有JTAG和SW两种,JTAG接口因为需要的管脚较多,故此仅在一些学习用的开发板上能够见到,批量化生产的产品中极少用到。而SW接口仅需要两个管脚(PA13和PA14),是使用较为普遍的调试接口。做为调试专用管脚,一旦在程序中将其设置为了普通GPIO,若想再通过SW调试则必须通过ISP方式下载新的程序(没有进行GPIO设置的程序),给调试带来很多不便。下面讨论如何做到PA13和PA14如果即能保证正常调试功能又可当GPIO的方法。
(1)做为输入管脚
当使用调试接口做为输出时,不需要进行什么特殊设置,在任何时候直接使用读取语句读取即可,不会影响到SW调试功能。
GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_13);//读取PA13(SW_DAT)电平
GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_14);//读取PA14(SW_CLK)电平
(2)做为输出管脚
在程序开始时判断当前是否连接了SW调试器,若未连接时才去设置PA13和PA14为输出GPIO。
重点是如何判断是否连接了调试器,我对STM32的函数库并不是特别熟悉,经过简单不负责任的寻找后并没有发现有这方面的现成函数,所以就土法上马了。
我们知道,如果连接了调试器时,不管是CLK还是DAT管脚,都会有无数的方波(调试嘛,一定是有方波的,要不然怎么进行数据交互),既然任何时候都可以用读取指令获取管脚的电平状态,那么只要判断一下是不是有电平变化就可以了(方波),下面是个粗暴的判断函数。
unsigned char PA14IsDBG=0;
unsigned char CheckPA14IsDBG(void)
{
unsigned short i,j,s;
if (PA14IsDBG==1) return 1;// PA14IsDBG是全局变量
for (i=0;i<100;i++)
{
s=GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_14);
for (j=0;j<1000;j++)
{
if (GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_14)!=s)
{
PA14IsDBG=1;
UART1_SendString("Is Debug\r\n");
return 1;
}
//__NOP();
}
}
return 0;
}
上面的函数是使用PA14(SW_CLK)管脚进行检测,若使用PA13(SW_DAT)也同样是可以的。
设置PA14(SW_CLK)为输出
void SetPA14IsOut(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
If (PA14IsDBG) return;
GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable,ENABLE);//完全禁用调试接口
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA||RCC_APB2Periph_AFIO, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;//一定要是开漏输出
//GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
void SetPA14IsDbg(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);//使能SW调试接口
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA||RCC_APB2Periph_AFIO, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
//GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
//设置PA14输出高低电平
void PA14OutH(void)
{
if (PA14IsDBG) return;
GPIO_SetBits(GPIOA, GPIO_Pin_14);
}
void PA14OutL(void)
{
if (PA14IsDBG) return;
GPIO_ResetBits(GPIOA, GPIO_Pin_14);
}
void main(void)
{
CheckPA14IsDBG();
SetPA14IsOut();
while (1)
{
PA14OutH();
Delay_ms(500);
PA14OutL();
Delay_ms(500);
CheckPA14IsDBGLK();
if (PA14IsDBG) SetPA14IsDbg();
}
}
需要注意的几点:
(1)上电后,必须迟早调用CheckPA14IsDBG();
(2)在整个程序中,仅可调用一次SetPA14IsOut();且必须在CheckPA14IsDBG();之后。
(3)PA13或者PA14做为输出时,只能配置为开漏输出,这一点非常重要(其实修改一下代码也可以强推挽,明白其中原理就没有问题)。
(4)在程序运行过程中,要经常调用CheckPA14IsDBG();来检测是否有调试信号出现,以便恢复为SW功能。
(5)若单片机曾经在非调试状态运行过,则再次调试时可能失败,多试几次就好了。
(6)以上代码使用了PA14,同样适用于PA13,将代码中的PA14改为PA13即可。
|