后臺有許多讀者留言說先弄點干貨。今天應(yīng)讀者要求,我們先來一篇干貨。大家有什么要求,歡迎留言,關(guān)于MCU的應(yīng)用、測試要求,我們都會盡量滿足。
在上兩期文章和視頻中,為了公平起見,所有的MCU使用的是同一個工程程序,(不同的MCU,時鐘和GPIO的配置略有不同,使用宏定義區(qū)分MCU),除了使用滴答時鐘和基本GPIO操作外,沒有任何抗干擾手段,全靠MCU內(nèi)部自身的抗干擾能力進行的測試。結(jié)果,只有芯源CW32MCU沒有徹底死機外,其它均有死機現(xiàn)象。
這種死機現(xiàn)象,在我們實際開發(fā)產(chǎn)品時,是禁止發(fā)生的。為了對付這種干擾,除了硬件上有些技術(shù)對策,那軟件上又有些什么呢?
當然是我們最熟悉的看門狗了?!翱撮T狗”這個神器在“古老的年代”51時期,那是沒有的,需要在外面加一個“昂貴”的芯片來實現(xiàn)。當然,現(xiàn)在新時代,所有的ARM MCU基本上都標配了看門狗外設(shè)。
看門狗是啥,我們來看一下,STM32芯片的用戶手冊,關(guān)于看門狗的介紹。
▲圖1
這里我們就不詳細展開其內(nèi)容了。直接來看核心代碼。
//摘要: /* 系統(tǒng)時鐘,使用內(nèi)部高速HSI倍數(shù),系統(tǒng)時鐘為48M。 */ //Programed by Cache.Lee 2023.1.4 #include "stm32f0xx.h" #include "stm32f0xx_gpio.h" //GPIOA #define SEGA GPIO_Pin_10 #define SEGB GPIO_Pin_9 #define SEGC GPIO_Pin_8 //GPIOB #define SEGD GPIO_Pin_14 #define SEGE GPIO_Pin_15 //GPIOA #define SEGF GPIO_Pin_11 #define SEGG GPIO_Pin_12 //GPIOB #define SEGDP GPIO_Pin_13 //num:需要顯示的數(shù)字,no:0顯示左邊數(shù)碼管,1顯示右邊數(shù)碼管 void SEG_DisplayNum(unsigned int num, unsigned int no) { GPIO_ResetBits(GPIOA,0xffff);//關(guān)段碼、位碼 GPIO_ResetBits(GPIOB,0xffff);//關(guān)段碼、位碼 switch(num) //開段碼 { case 0: //ABCDEF GPIO_SetBits(GPIOA,SEGA|SEGB|SEGC|SEGF); GPIO_SetBits(GPIOB,SEGD|SEGE); break; case 1: //BC GPIO_SetBits(GPIOA,SEGB|SEGC); break; case 2: //ABDEG GPIO_SetBits(GPIOA,SEGA|SEGB|SEGG); GPIO_SetBits(GPIOB,SEGD|SEGE); break; case 3: //ABCDG GPIO_SetBits(GPIOA,SEGA|SEGB|SEGC|SEGG); GPIO_SetBits(GPIOB,SEGD); break; case 4://BCFG GPIO_SetBits(GPIOA,SEGF|SEGB|SEGC|SEGG); break; case 5://ACDFG GPIO_SetBits(GPIOA,SEGA|SEGC|SEGG|SEGF); GPIO_SetBits(GPIOB,SEGD); break; case 6: //ACDEFG GPIO_SetBits(GPIOA,SEGA|SEGC|SEGG|SEGF); GPIO_SetBits(GPIOB,SEGD|SEGE); break; case 7: //ABC GPIO_SetBits(GPIOA,SEGA|SEGB|SEGC); break; case 8: //ABCDEFG GPIO_SetBits(GPIOA,SEGA|SEGB|SEGC|SEGG|SEGF); GPIO_SetBits(GPIOB,SEGD|SEGE); break; case 9: //ABCDFG GPIO_SetBits(GPIOA,SEGA|SEGB|SEGC|SEGG|SEGF); GPIO_SetBits(GPIOB,SEGD); break; case 10: //DP 顯示DP GPIO_SetBits(GPIOB,SEGDP); break; default: break; } if(no==1) GPIO_SetBits(GPIOB,GPIO_Pin_12); else GPIO_SetBits(GPIOB,GPIO_Pin_11);//關(guān)位碼 } void GPIOInit(void) { GPIO_InitTypeDef GPIO_InitStructure; //數(shù)碼管斷碼位碼 IO初始化 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE); RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11|GPIO_Pin_12; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11|GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15; GPIO_Init(GPIOB, &GPIO_InitStructure); } int main(void) { unsigned long i; unsigned int num=0; for(i=0;i<60000;i++); //上電延時 GPIOInit(); /* IWDG timeout equal to 250 ms (the timeout may varies due to LSI frequency dispersion) */ /* Enable write access to IWDG_PR and IWDG_RLR registers */ IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable); /* IWDG counter clock: LSI/32 */ IWDG_SetPrescaler(IWDG_Prescaler_32); /* Set counter reload value to obtain 250ms IWDG TimeOut. Counter Reload Value = 250ms/IWDG counter clock period = 250ms / (LSI/32) = 0.25s / (LsiFreq/32) = LsiFreq/(32 * 4) = LsiFreq/128 */ IWDG_SetReload(40000/128); /* Reload IWDG counter */ IWDG_ReloadCounter(); /* Enable IWDG (the LSI oscillator will be enabled by hardware) */ IWDG_Enable(); SEG_DisplayNum(10,1); for(i=0;i<60000;i++); while(1) { num++; if(num>=100)num=0; SEG_DisplayNum(num/10,0); for(i=0;i<60000;i++); //延時 SEG_DisplayNum(num%10,1); for(i=0;i<60000;i++); //延時 SEG_DisplayNum(num/10,0); for(i=0;i<60000;i++); //延時 IWDG_ReloadCounter(); //喂狗 SEG_DisplayNum(num%10,1); for(i=0;i<60000;i++); //延時 SEG_DisplayNum(num/10,0); for(i=0;i<60000;i++); //延時 SEG_DisplayNum(num%10,1); for(i=0;i<60000;i++); //延時 IWDG_ReloadCounter(); //喂狗 } }
這里的代碼與上期代碼不同,我們使用官方標準庫來重新編寫。其中數(shù)碼管的動態(tài)掃描沒有使用滴答時鐘,而是在主程序中直接用延時來完成。區(qū)別于之前的代碼,我們增加了獨立看門狗的功能??撮T狗的喂狗操作在MAIN函數(shù)的大循環(huán)里,數(shù)碼管的動態(tài)掃描中實現(xiàn)。
當程序發(fā)生死機時,MAIN函數(shù)的大循環(huán)將暫停運行,數(shù)碼管隨機顯示最近一次數(shù)值,不進行動態(tài)掃描,所以,只有一位數(shù)碼管顯示。同時,喂狗暫停。當看門狗時間到,將發(fā)生看門狗復(fù)位操作,系統(tǒng)將重新復(fù)位運行。這樣程序就實現(xiàn)了看門狗復(fù)位功能。
在實驗中,由于打狗棒電壓干擾的威力巨大,STM32芯片被打壞了幾個引腳。驅(qū)動A、F、G的端口功能異常,而且芯片略燙,應(yīng)該是引腳被打壞了。但不影響下載,其它位碼顯示正常。
除了看門狗復(fù)位,還有一種軟件復(fù)位方式。當MCU發(fā)生硬件失效時,會進入Hardfault中數(shù)函數(shù)。Hardfault是優(yōu)先級別為-1的固定類型中斷,無需初始化設(shè)置。常常在MCU死機時,不知明的會進入Hardfault中斷。因此,在Hardfault中斷函數(shù)中,添加軟件復(fù)位功能也是一種防死機現(xiàn)象的方法。代碼如下:
void HardFault_Handler(void) { unsigned int j; /* Go to infinite loop when Hard Fault exception occurs */ while (1) { SEG_DisplayNum(10,0); for(j=0;j<60000;j++); for(j=0;j<60000;j++); for(j=0;j<60000;j++); for(j=0;j<60000;j++); for(j=0;j<60000;j++); for(j=0;j<60000;j++); NVIC_SystemReset(); } }
審核編輯黃宇
-
mcu
+關(guān)注
關(guān)注
146文章
17185瀏覽量
351729 -
看門狗
+關(guān)注
關(guān)注
10文章
565瀏覽量
70863 -
STM32
+關(guān)注
關(guān)注
2270文章
10910瀏覽量
356612 -
時鐘
+關(guān)注
關(guān)注
11文章
1736瀏覽量
131589 -
抗干擾
+關(guān)注
關(guān)注
4文章
319瀏覽量
34602
發(fā)布評論請先 登錄
相關(guān)推薦
評論