鱼和熊掌兼得---STM32调试接口SW动态复用为GPIO的方法

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即可。

 

你可能感兴趣的:(单片机技术)