文章目錄:
一:低功耗模式
1.睡眠模式測(cè)試程序
NVIC.h
NVIC.c
key.h
key.c
main.c
2.停機(jī)模式測(cè)試程序
main.c
3.待機(jī)模式測(cè)試程序
main.c
二:看門(mén)狗
1.獨(dú)立看門(mén)狗測(cè)試程序
iwdg.h
iwdg.c
main.c
2.窗口看門(mén)狗測(cè)試程序
wwdg.h
wwdg.c
main.c
三:TIM定時(shí)器
tim.h
tim.c
main.c
四:CRC循環(huán)冗余校驗(yàn)計(jì)算單元與芯片ID
1.CRC功能測(cè)試程序
main.c
2.芯片ID讀取程序
main.c
五:還需要補(bǔ)充的知識(shí)
這些是單片機(jī)的輔助功能
一:低功耗模式
單片機(jī)內(nèi)部功率是各功能部分功率的總和 低功耗模式是通過(guò)關(guān)掉部分內(nèi)部功能達(dá)到省電 STM32F103單片機(jī)共有3種低功耗模式 不同模式會(huì)對(duì)系統(tǒng)正常工作有一定影響,需要按實(shí)際情況選擇 低功耗模式只針對(duì)單片機(jī)內(nèi)部功能,外接電路產(chǎn)生的功耗不在其內(nèi) 單片機(jī)最小系統(tǒng)電路功耗,不精確測(cè)量值 √正常模式:10mA √睡眠模式:2mA √停機(jī)模式:20uA √待機(jī)模式:2uA 睡眠模式 在ARM內(nèi)核無(wú)事可做的時(shí)候,可以進(jìn)入睡眠模式 例如:電腦的CPU空閑狀態(tài)就是單片機(jī)睡眠模式 睡眠模式的應(yīng)用不多,因只關(guān)閉ARM內(nèi)核,節(jié)能有限,很少在非操作系統(tǒng)程序(裸機(jī))中使用 在嵌入式操作系統(tǒng)中,會(huì)采用睡眠模式 優(yōu)點(diǎn):對(duì)系統(tǒng)影響最小 缺點(diǎn):節(jié)能效果最差 停機(jī)模式 因SRAM內(nèi)容不消失,程序不復(fù)位,可在喚醒后繼續(xù)運(yùn)行 節(jié)能效果與待機(jī)模式近似,卻有著更多優(yōu)勢(shì) 主要用于電池供電的設(shè)備上,提高電池壽命 在電池供電的產(chǎn)品中必須使用,在外部供電的產(chǎn)品中沒(méi)必要使用 優(yōu)點(diǎn):節(jié)能效果好,程序不會(huì)復(fù)位 缺點(diǎn):恢復(fù)時(shí)間較長(zhǎng) 待機(jī)模式 由于SRAM內(nèi)容消失,喚醒后程序必須復(fù)位,從頭開(kāi)始運(yùn)行 因?yàn)榇龣C(jī)和停機(jī)之間的功耗差別是uA級(jí)的,幾乎沒(méi)有差別,所以開(kāi)發(fā)者大多使用停機(jī)模式,待機(jī)模式極少使用 在一些偶爾需要工作的場(chǎng)合,且工作量不大、不復(fù)雜的情況下,待機(jī)模式可以保證最低的功耗 比如應(yīng)用在室外溫度測(cè)量產(chǎn)品上,每1小時(shí)測(cè)量一次??捎肦TC鬧鐘喚醒,測(cè)量完再待機(jī)。、 優(yōu)點(diǎn):最節(jié)能 缺點(diǎn):程序會(huì)復(fù)位,只有少數(shù)條件可喚醒
?
1.睡眠模式測(cè)試程序
NVIC.h
#ifndef __NVIC_H #define __NVIC_H #include "sys.h" extern u8 INT_MARK;//中斷標(biāo)志位 void KEY_INT_INIT (void); #endif
NVIC.c
#include "NVIC.h" u8 INT_MARK;//中斷標(biāo)志位 void KEY_INT_INIT (void){ //按鍵中斷初始化 NVIC_InitTypeDef NVIC_InitStruct; //定義結(jié)構(gòu)體變量 EXTI_InitTypeDef EXTI_InitStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //啟動(dòng)GPIO時(shí)鐘 (需要與復(fù)用時(shí)鐘一同啟動(dòng)) RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO , ENABLE);//配置端口中斷需要啟用復(fù)用時(shí)鐘 GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0); //定義 GPIO 中斷 EXTI_InitStruct.EXTI_Line=EXTI_Line0; //定義中斷線 EXTI_InitStruct.EXTI_LineCmd=ENABLE; //中斷使能 EXTI_InitStruct.EXTI_Mode=EXTI_Mode_Interrupt; //中斷模式為 中斷 EXTI_InitStruct.EXTI_Trigger=EXTI_Trigger_Falling; //下降沿觸發(fā) EXTI_Init(& EXTI_InitStruct); NVIC_InitStruct.NVIC_IRQChannel=EXTI0_IRQn; //中斷線 NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE; //使能中斷 NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2; //搶占優(yōu)先級(jí) 2 NVIC_InitStruct.NVIC_IRQChannelSubPriority=2; //子優(yōu)先級(jí) 2 NVIC_Init(& NVIC_InitStruct); } void EXTI0_IRQHandler(void){ if(EXTI_GetITStatus(EXTI_Line0)!=RESET){//判斷某個(gè)線上的中斷是否發(fā)生 INT_MARK=1;//標(biāo)志位置1,表示有按鍵中斷 EXTI_ClearITPendingBit(EXTI_Line0); //清除 LINE 上的中斷標(biāo)志位 } }
key.h
#ifndef __KEY_H #define __KEY_H #include "sys.h" //#define KEY1 PAin(0)// PA0 //#define KEY2 PAin(1)// PA1 #define KEYPORT GPIOA //定義IO接口組 #define KEY1 GPIO_Pin_0 //定義IO接口 #define KEY2 GPIO_Pin_1 //定義IO接口 void KEY_Init(void);//初始化 #endif
key.c
#include "key.h" void KEY_Init(void){ //微動(dòng)開(kāi)關(guān)的接口初始化 GPIO_InitTypeDef GPIO_InitStructure; //定義GPIO的初始化枚舉結(jié)構(gòu) RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); GPIO_InitStructure.GPIO_Pin = KEY1 | KEY2; //選擇端口號(hào)(0~15或all) GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //選擇IO接口工作方式 //上拉電阻 // GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //設(shè)置IO接口速度(2/10/50MHz) GPIO_Init(KEYPORT,&GPIO_InitStructure); }
main.c
#include "stm32f10x.h" //STM32頭文件 #include "sys.h" #include "delay.h" #include "relay.h" #include "oled0561.h" #include "led.h" #include "key.h" #include "NVIC.h" //中斷向量控制器 int main (void){//主程序 delay_ms(500); //上電時(shí)等待其他器件就緒 RCC_Configuration(); //系統(tǒng)時(shí)鐘初始化 RELAY_Init();//繼電器初始化 LED_Init();//LED KEY_Init();//KEY I2C_Configuration();//I2C初始化 OLED0561_Init(); //OLED初始化 OLED_DISPLAY_8x16_BUFFER(0," SLEEP TEST "); //顯示字符串 INT_MARK=0;//標(biāo)志位清0 NVIC_Configuration();//設(shè)置中斷優(yōu)先級(jí) KEY_INT_INIT();//按鍵中斷初始化(PA0是按鍵中斷輸入) NVIC_SystemLPConfig(NVIC_LP_SEVONPEND,DISABLE); //SEVONPEND: 0:只有使能的中斷或事件才能喚醒內(nèi)核。1:任何中斷和事件都可以喚醒內(nèi)核。(0=DISABLE,1=ENABLE) NVIC_SystemLPConfig(NVIC_LP_SLEEPDEEP,DISABLE); //SLEEPDEEP: 0:低功耗模式為睡眠模式。1:進(jìn)入低功耗時(shí)為深度睡眠模式。 NVIC_SystemLPConfig(NVIC_LP_SLEEPONEXIT,DISABLE); //SLEEPONEXIT: 0: 被喚醒進(jìn)入線程模式后不再進(jìn)入睡眠模式。1:被喚醒后執(zhí)行完相應(yīng)的中斷處理函數(shù)后進(jìn)入睡眠模式。 while(1){ GPIO_WriteBit(LEDPORT,LED1,(BitAction)(1)); //LED控制 OLED_DISPLAY_8x16_BUFFER(4," CPU SLEEP! "); //顯示字符串 delay_ms(500); // __WFI(); //進(jìn)入睡眠模式,等待中斷喚醒 // __WFE(); //進(jìn)入睡眠模式,等待事件喚醒 GPIO_WriteBit(LEDPORT,LED1,(BitAction)(0)); //LED控制 OLED_DISPLAY_8x16_BUFFER(4," CPU WAKE UP! "); //顯示字符串 delay_ms(500); // } }
2.停機(jī)模式測(cè)試程序
main.c
#include "stm32f10x.h" //STM32頭文件 #include "sys.h" #include "delay.h" #include "relay.h" #include "oled0561.h" #include "led.h" #include "key.h" #include "NVIC.h" int main (void){//主程序 delay_ms(500); //上電時(shí)等待其他器件就緒 RCC_Configuration(); //系統(tǒng)時(shí)鐘初始化 RELAY_Init();//繼電器初始化 LED_Init();//LED KEY_Init();//KEY I2C_Configuration();//I2C初始化 OLED0561_Init(); //OLED初始化 OLED_DISPLAY_8x16_BUFFER(0," STOP TEST "); //顯示字符串 INT_MARK=0;//標(biāo)志位清0 NVIC_Configuration();//設(shè)置中斷優(yōu)先級(jí) KEY_INT_INIT();//按鍵中斷初始化(PA0是按鍵中斷輸入) RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE); //使能電源PWR時(shí)鐘 while(1){ GPIO_WriteBit(LEDPORT,LED1,(BitAction)(1)); //LED控制 OLED_DISPLAY_8x16_BUFFER(4," CPU STOP! "); //顯示字符串 delay_ms(500); // PWR_EnterSTOPMode(PWR_Regulator_LowPower,PWR_STOPEntry_WFI);//進(jìn)入停機(jī)模式 RCC_Configuration(); //系統(tǒng)時(shí)鐘初始化(停機(jī)喚醒后會(huì)改用HSI時(shí)鐘,需要重新對(duì)時(shí)鐘初始化) GPIO_WriteBit(LEDPORT,LED1,(BitAction)(0)); //LED控制 OLED_DISPLAY_8x16_BUFFER(4," CPU WAKE UP! "); //顯示字符串 delay_ms(500); // } }
3.待機(jī)模式測(cè)試程序
對(duì)開(kāi)發(fā)板跳線進(jìn)行設(shè)置
觸摸按鍵將最上方的PA0跳線斷開(kāi)
?
main.c
#include "stm32f10x.h" //STM32頭文件 #include "sys.h" #include "delay.h" #include "relay.h" #include "oled0561.h" #include "led.h" int main (void){//主程序 delay_ms(500); //上電時(shí)等待其他器件就緒 RCC_Configuration(); //系統(tǒng)時(shí)鐘初始化 RELAY_Init();//繼電器初始化 LED_Init();//LED I2C_Configuration();//I2C初始化 OLED0561_Init(); //OLED初始化 OLED_DISPLAY_8x16_BUFFER(0," STANDBY TEST "); //顯示字符串 RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE); //使能電源PWR時(shí)鐘 PWR_WakeUpPinCmd(ENABLE);//WKUP喚醒功能開(kāi)啟(待機(jī)時(shí)WKUP腳PA0為模擬輸入) GPIO_WriteBit(LEDPORT,LED1,(BitAction)(0)); //LED控制 OLED_DISPLAY_8x16_BUFFER(4," CPU RESET! "); //顯示字符串 delay_ms(500); // GPIO_WriteBit(LEDPORT,LED1,(BitAction)(1)); //LED控制 OLED_DISPLAY_8x16_BUFFER(4," STANDBY! "); //顯示字符串 delay_ms(500); // PWR_EnterSTANDBYMode();//進(jìn)入待機(jī)模式 //因?yàn)榇龣C(jī)喚醒后程序從頭運(yùn)行,所以不需要加while(1)的主循環(huán)體。 }
二:看門(mén)狗
是單片機(jī)系統(tǒng)功能的一個(gè)輔助功能:幫助單片機(jī)自我檢查、?監(jiān)控單片機(jī)程序是否正常工作
看門(mén)狗定時(shí)器(WDT,Watch Dog Timer)是單片機(jī)的一個(gè)組成部分 它實(shí)際上是一個(gè)計(jì)數(shù)器,一般給看門(mén)狗計(jì)數(shù)值,程序開(kāi)始運(yùn)行后看門(mén)狗開(kāi)始倒計(jì)數(shù) 如果程序運(yùn)行正常,過(guò)一段時(shí)間CPU應(yīng)發(fā)出指令讓看門(mén)狗復(fù)位,重新開(kāi)始倒計(jì)數(shù) 如果看門(mén)狗減到0就認(rèn)為程序沒(méi)有正常工作,強(qiáng)制整個(gè)系統(tǒng)復(fù)位 看門(mén)狗是一個(gè)計(jì)數(shù)器 啟動(dòng)后開(kāi)始倒計(jì)時(shí) 每過(guò)一段時(shí)間CPU要重新寫(xiě)入計(jì)數(shù)值(喂狗) CPU能重寫(xiě)計(jì)數(shù)值,表示程序運(yùn)行正常 如果程序運(yùn)行出錯(cuò)或死機(jī),則不能重寫(xiě)計(jì)數(shù)值 當(dāng)計(jì)數(shù)值減到O時(shí),看門(mén)狗會(huì)讓整個(gè)單片機(jī)復(fù)位 看門(mén)狗的作用 看門(mén)狗的主要目的是監(jiān)控單片機(jī)程序 如果程序不斷喂狗,就證明單片機(jī)工作正常 如果程序沒(méi)有喂狗,就說(shuō)明單片機(jī)出了問(wèn)題 看門(mén)狗不能檢查問(wèn)題的原因,只能通過(guò)復(fù)位單片機(jī),讓程序重新開(kāi)始運(yùn)行 類型:獨(dú)立看門(mén)狗、窗口看門(mén)狗
獨(dú)立看門(mén)狗可在計(jì)數(shù)到O前隨時(shí)喂狗 用于監(jiān)控程序是否正常運(yùn)行
?
窗口看門(mén)狗必須在規(guī)定的時(shí)間范圍內(nèi)喂狗 作用是監(jiān)控單片機(jī)運(yùn)行時(shí)效是否精確
?
1.獨(dú)立看門(mén)狗測(cè)試程序
?新建文件夾
Basic文件夾——>iwdg文件夾——>iwdg.c iwdg.h
iwdg.h
#ifndef __IWDG_H #define __IWDG_H #include "sys.h" //看門(mén)狗定時(shí)時(shí)間計(jì)算公式:Tout=(預(yù)分頻值*重裝載值)/40 (單位:ms) //當(dāng)前pre為64,rlr為625,計(jì)算得到Tout時(shí)間為1秒(大概值)。 #define pre IWDG_Prescaler_64 //分頻值范圍:4,8,16,32,64,128,256 #define rlr 625 //重裝載值范圍:0~0xFFF(4095) void IWDG_Init(void); void IWDG_Feed(void); #endif
iwdg.c
#include "iwdg.h" void IWDG_Init(void){ //初始化獨(dú)立看門(mén)狗 IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable); //使能對(duì)寄存器IWDG_PR和IWDG_RLR的寫(xiě)操作 IWDG_SetPrescaler(pre); //設(shè)置IWDG預(yù)分頻值 IWDG_SetReload(rlr); //設(shè)置IWDG重裝載值 IWDG_ReloadCounter(); //按照IWDG重裝載寄存器的值重裝載IWDG計(jì)數(shù)器 IWDG_Enable(); //使能IWDG } void IWDG_Feed(void){ //喂狗程序 IWDG_ReloadCounter();//固件庫(kù)的喂狗函數(shù) }
main.c
#include "stm32f10x.h" //STM32頭文件 #include "sys.h" #include "delay.h" #include "relay.h" #include "oled0561.h" #include "led.h" #include "key.h" #include "iwdg.h" int main (void){//主程序 delay_ms(500); //上電時(shí)等待其他器件就緒 RCC_Configuration(); //系統(tǒng)時(shí)鐘初始化 RELAY_Init();//繼電器初始化 LED_Init();//LED KEY_Init();//KEY I2C_Configuration();//I2C初始化 OLED0561_Init(); //OLED初始化---------------" OLED_DISPLAY_8x16_BUFFER(0," IWDG TEST "); //顯示字符串 OLED_DISPLAY_8x16_BUFFER(4," RESET! "); //顯示字符串 delay_ms(800); // OLED_DISPLAY_8x16_BUFFER(4," "); //顯示字符串 IWDG_Init(); //初始化并啟動(dòng)獨(dú)立看門(mén)狗 while(1){ IWDG_Feed(); //喂狗 if(!GPIO_ReadInputDataBit(KEYPORT,KEY1)){ delay_s(2); //延時(shí)2秒,使程序不能喂狗而導(dǎo)致復(fù)制 } } }
2.窗口看門(mén)狗測(cè)試程序
?新建文件夾
Basic文件夾——>wwdg文件夾——>wwdg.c wwdg.h
wwdg.h
#ifndef __WWDG_H #define __WWDG_H #include "sys.h" //窗口看門(mén)狗定時(shí)時(shí)間計(jì)算公式: //上窗口超時(shí)時(shí)間(單位us) = 4096*預(yù)分頻值*(計(jì)數(shù)器初始值-窗口值)/APB1時(shí)鐘頻率(單位MHz) //下窗口超時(shí)時(shí)間(單位us) = 4096*預(yù)分頻值*(計(jì)數(shù)器初始值-0x40)/APB1時(shí)鐘頻率(單位MHz) #define WWDG_CNT 0x7F //計(jì)數(shù)器初始值,范圍:0x40~0x7F #define wr 0x50 //窗口值(上窗口邊界),范圍:0x40~0x7F #define fprer WWDG_Prescaler_8 //預(yù)分頻值,取值:1,2,4,8 //如上三個(gè)值是:0x7f,0x50,8時(shí),上窗口48MS,下窗口64MS。 void WWDG_Init(void); void WWDG_NVIC_Init(void); void WWDG_Feed(void); #endif
wwdg.c
#include "wwdg.h" void WWDG_Init(void){ //初始化窗口看門(mén)狗 RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); // WWDG 時(shí)鐘使能 WWDG_SetPrescaler(fprer); //設(shè)置 IWDG 預(yù)分頻值 WWDG_SetWindowValue(wr); //設(shè)置窗口值 WWDG_Enable(WWDG_CNT); //使能看門(mén)狗,設(shè)置 counter WWDG_ClearFlag(); //清除提前喚醒中斷標(biāo)志位 WWDG_NVIC_Init(); //初始化窗口看門(mén)狗 NVIC WWDG_EnableIT(); //開(kāi)啟窗口看門(mén)狗中斷 } void WWDG_NVIC_Init(void){ //窗口看門(mén)狗中斷服務(wù)程序(被WWDG_Init調(diào)用) NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn; //WWDG 中斷 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //搶占 2 子優(yōu)先級(jí) 3 組 2 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //搶占 2,子優(yōu)先級(jí) 3,組 2 NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; NVIC_Init(&NVIC_InitStructure); //NVIC 初始化 } void WWDG_Feed(void){ //窗口喂狗程序 WWDG_SetCounter(WWDG_CNT); //固件庫(kù)的喂狗函數(shù) } void WWDG_IRQHandler(void){ //窗口看門(mén)狗中斷處理程序 WWDG_ClearFlag(); //清除提前喚醒中斷標(biāo)志位 //此處加入在復(fù)位前需要處理的工作或保存數(shù)據(jù) }
main.c
#include "stm32f10x.h" //STM32頭文件 #include "sys.h" #include "delay.h" #include "relay.h" #include "oled0561.h" #include "led.h" #include "key.h" #include "wwdg.h" int main (void){//主程序 delay_ms(500); //上電時(shí)等待其他器件就緒 RCC_Configuration(); //系統(tǒng)時(shí)鐘初始化 RELAY_Init();//繼電器初始化 LED_Init();//LED KEY_Init();//KEY I2C_Configuration();//I2C初始化 OLED0561_Init(); //OLED初始化---------------" OLED_DISPLAY_8x16_BUFFER(0," WWDG TEST "); //顯示字符串 OLED_DISPLAY_8x16_BUFFER(4," RESET! "); //顯示字符串 delay_ms(800); // OLED_DISPLAY_8x16_BUFFER(4," "); //顯示字符串 WWDG_Init(); //初始化并啟動(dòng)獨(dú)立看門(mén)狗 while(1){ delay_ms(54); //用延時(shí)找到喂狗的窗口時(shí)間 避開(kāi)計(jì)數(shù)初始值到上窗口邊界這段時(shí)間 WWDG_Feed(); //喂狗 if(!GPIO_ReadInputDataBit(KEYPORT,KEY1)){ delay_s(2); //延時(shí)2秒,使程序不能喂狗而導(dǎo)致復(fù)制 } } }
三:TIM定時(shí)器
?
定時(shí)器的3種功能 捕獲器:測(cè)量波形的頻率和寬度 比較器:分為模擬比較器和輸出比較器 模擬比較器:比較兩組輸入電壓的大小(STM32F103無(wú)此功能) 輸出比較器:產(chǎn)生可調(diào)頻率和可調(diào)占空比的脈沖波形 PWM:脈寬調(diào)制器,產(chǎn)生固定頻率但占空比可調(diào)的脈沖波形 普通定時(shí)器 定時(shí)器可以用于獨(dú)立時(shí)間計(jì)時(shí)功能,原理和嘀嗒定時(shí)器、看門(mén)狗基本相同 定時(shí)時(shí)間到時(shí),可等待CPU檢查標(biāo)志位(查尋方式),或產(chǎn)生“定時(shí)器中斷” —般都是讓定時(shí)器產(chǎn)生中斷 捕獲器 捕獲什么? 輸入接口的電平變化(上升沿或下降沿) 上升沿:從低電平到高電平 下降沿:從高電平到低電平 有什么用? 可測(cè)量脈沖的寬度,或者測(cè)量脈沖頻率 寬度 T1是上沿捕獲的定時(shí)器值 T2是下沿捕獲的定時(shí)器值 T2-T1=高電平寬度值 頻率 T1是第1次上沿捕獲值 T2是第2次上沿捕獲值 T2-T1=一個(gè)周期時(shí)間值(頻率) 工作過(guò)程! 當(dāng)接口產(chǎn)生上升沿或下降沿時(shí),將當(dāng)前定時(shí)器值保存 輸出比較器 可輸出脈沖,可調(diào)占空比和頻率 每一個(gè)周期的長(zhǎng)度都可以不同 每一個(gè)周期內(nèi)的占空比都可以不同 PWM只能調(diào)占空比(也是可以通過(guò)程序調(diào)頻率,但不方便隨時(shí)調(diào)) 輸出比較器可隨時(shí)調(diào)占空比和頻率 輸出比較器主要用于步進(jìn)電機(jī)、伺服電機(jī)的控制
定時(shí)器中斷測(cè)試程序
?新建文件夾
Basic文件夾——>tim文件夾——>tim.c tim.h
tim.h
#ifndef __PWM_H #define __PWM_H #include "sys.h" void TIM3_Init(u16 arr,u16 psc); void TIM3_NVIC_Init (void); #endif
tim.c
#include "led.h" //因在中斷處理函數(shù)中用到LED驅(qū)動(dòng) #include "tim.h" //定時(shí)器時(shí)間計(jì)算公式Tout = ((重裝載值+1)*(預(yù)分頻系數(shù)+1))/時(shí)鐘頻率; //例如:1秒定時(shí),重裝載值=9999,預(yù)分頻系數(shù)=7199 void TIM3_Init(u16 arr,u16 psc){ //TIM3 初始化 arr重裝載值 psc預(yù)分頻系數(shù) TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStrue; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//使能TIM3 TIM3_NVIC_Init (); //開(kāi)啟TIM3中斷向量 TIM_TimeBaseInitStrue.TIM_Period=arr; //設(shè)置自動(dòng)重裝載值 TIM_TimeBaseInitStrue.TIM_Prescaler=psc; //預(yù)分頻系數(shù) TIM_TimeBaseInitStrue.TIM_CounterMode=TIM_CounterMode_Up; //計(jì)數(shù)器向上溢出 TIM_TimeBaseInitStrue.TIM_ClockDivision=TIM_CKD_DIV1; //時(shí)鐘的分頻因子,起到了一點(diǎn)點(diǎn)的延時(shí)作用,一般設(shè)為T(mén)IM_CKD_DIV1 TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStrue); //TIM3初始化設(shè)置 TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);//使能TIM3中斷 TIM_Cmd(TIM3,ENABLE); //使能TIM3 } void TIM3_NVIC_Init (void){ //開(kāi)啟TIM3中斷向量 NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x3; //設(shè)置搶占和子優(yōu)先級(jí) NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x3; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } void TIM3_IRQHandler(void){ //TIM3中斷處理函數(shù) if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET){ //判斷是否是TIM3中斷 TIM_ClearITPendingBit(TIM3, TIM_IT_Update); //此處寫(xiě)入用戶自己的處理程序 GPIO_WriteBit(LEDPORT,LED1,(BitAction)(1-GPIO_ReadOutputDataBit(LEDPORT,LED1))); //取反LED1 } }
main.c
#include "stm32f10x.h" //STM32頭文件 #include "sys.h" #include "delay.h" #include "relay.h" #include "oled0561.h" #include "led.h" #include "key.h" #include "tim.h" int main (void){//主程序 delay_ms(500); //上電時(shí)等待其他器件就緒 RCC_Configuration(); //系統(tǒng)時(shí)鐘初始化 RELAY_Init();//繼電器初始化 LED_Init();//LED KEY_Init();//KEY I2C_Configuration();//I2C初始化 OLED0561_Init(); //OLED初始化---------------" OLED_DISPLAY_8x16_BUFFER(0," TIM TEST "); //顯示字符串 TIM3_Init(9999,7199);//定時(shí)器初始化,定時(shí)1秒(9999,7199) while(1){ //寫(xiě)入用戶的程序 //LED1閃爍程序在TIM3的中斷處理函數(shù)中執(zhí)行 } }
四:CRC循環(huán)冗余校驗(yàn)計(jì)算單元與芯片ID
1.CRC功能測(cè)試程序
CRC(循環(huán)冗余校驗(yàn))計(jì)算單元 使用一個(gè)固定的多項(xiàng)式發(fā)生器,從一個(gè)32位的數(shù)據(jù)字產(chǎn)生一個(gè)CRC碼在眾多的應(yīng)用中,基于CRC的技術(shù)被用于驗(yàn)證數(shù)據(jù)傳輸或存儲(chǔ)的一致性 在EN/IEC 60335-1標(biāo)準(zhǔn)的范圍內(nèi),它提供了一種檢測(cè)閃存存儲(chǔ)器錯(cuò)誤的手段,CRC計(jì)算單元可以用于實(shí)時(shí)地計(jì)算軟件的簽名,并與在鏈接和生成該軟件時(shí)產(chǎn)生的簽名對(duì)比。 √CRC是用于數(shù)據(jù)正確性校驗(yàn)的 √由一個(gè)32位的數(shù)據(jù)字產(chǎn)生√可應(yīng)用在FALSH檢測(cè) √可用于軟件簽名及對(duì)比 特點(diǎn):寫(xiě)入和讀出都是同一個(gè)寄存器,但內(nèi)容卻不同
?
main.c
#include "stm32f10x.h" //STM32頭文件 #include "sys.h" #include "delay.h" #include "relay.h" #include "oled0561.h" #include "led.h" #include "key.h" int main (void){//主程序 u32 a,b; u8 c; u32 y[3]={0x87654321,0x98765432,0x09876543}; delay_ms(500); //上電時(shí)等待其他器件就緒 RCC_Configuration(); //系統(tǒng)時(shí)鐘初始化 RELAY_Init();//繼電器初始化 LED_Init();//LED KEY_Init();//KEY I2C_Configuration();//I2C初始化 OLED0561_Init(); //OLED初始化---------------" OLED_DISPLAY_8x16_BUFFER(0," CRC TEST "); //顯示字符串 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_CRC, ENABLE);//開(kāi)啟CRC時(shí)鐘 while(1){ CRC_ResetDR();//復(fù)位CRC,需要清0重新計(jì)算時(shí)先復(fù)位 CRC_CalcCRC(0x12345678);//CRC計(jì)算一個(gè)32位數(shù)據(jù)。參數(shù):32位數(shù)據(jù)。返回值:32位計(jì)算結(jié)果 CRC_CalcCRC(0x23456789);//CRC計(jì)算一個(gè)32位數(shù)據(jù)。參數(shù):32位數(shù)據(jù)。返回值:32位計(jì)算結(jié)果 a = CRC_CalcCRC(0x34567890);//CRC計(jì)算一個(gè)32位數(shù)據(jù)。參數(shù):32位數(shù)據(jù)。返回值:32位計(jì)算結(jié)果 CRC_ResetDR();//復(fù)位CRC,需要清0重新計(jì)算時(shí)先復(fù)位 b = CRC_CalcBlockCRC(y,3);//CRC計(jì)算一個(gè)32位數(shù)組。參數(shù):32位數(shù)組名,數(shù)組長(zhǎng)度。返回值:32位計(jì)算結(jié)果 CRC_SetIDRegister(0x5a);//向獨(dú)立寄存器CRC_IDR寫(xiě)數(shù)據(jù)。參數(shù):8位數(shù)據(jù)。 c = CRC_GetIDRegister();//從獨(dú)立寄存器CRC_IDR讀數(shù)據(jù)。返回值:8位數(shù)據(jù)。 //此時(shí),a存放的是3個(gè)獨(dú)立數(shù)的CRC結(jié)果。(32位) //b存放的是數(shù)組y中3個(gè)數(shù)據(jù)CRC計(jì)算結(jié)果。(32位) //c存放的是我們寫(xiě)入的獨(dú)立寄存器數(shù)據(jù)0x5a。(8位) } } // 以下是CRC固件庫(kù)函數(shù),可在主程序中直接調(diào)用 // // RCC_AHBPeriphClockCmd(RCC_AHBPeriph_CRC, ENABLE);//開(kāi)啟CRC時(shí)鐘,主程序開(kāi)始時(shí)調(diào)用 // CRC_ResetDR();//復(fù)位CRC,需要清0重新計(jì)算時(shí)先復(fù)位 // uint32_t CRC_CalcCRC(uint32_t Data);//CRC計(jì)算一個(gè)32位數(shù)據(jù)。參數(shù):32位數(shù)據(jù)。返回值:32位計(jì)算結(jié)果 // uint32_t CRC_CalcBlockCRC(uint32_t pBuffer[], uint32_t BufferLength);//CRC計(jì)算一個(gè)32位數(shù)組。參數(shù):32位數(shù)組名,數(shù)組長(zhǎng)度。返回值:32位計(jì)算結(jié)果 // uint32_t CRC_GetCRC(void);//從CRC中讀出計(jì)算結(jié)果。返回值:32位計(jì)算結(jié)果。 // void CRC_SetIDRegister(uint8_t IDValue);//向獨(dú)立寄存器CRC_IDR寫(xiě)數(shù)據(jù)。參數(shù):8位數(shù)據(jù)。 // uint8_t CRC_GetIDRegister(void);//從獨(dú)立寄存器CRC_IDR讀數(shù)據(jù)。返回值:8位數(shù)據(jù)。
stm32f10x_crc.?c包含了CRC的固件庫(kù)函數(shù)
2.芯片ID讀取程序
芯片ID √ 96位ID編碼 √可讀出3個(gè)32位數(shù)據(jù),或8個(gè)8位數(shù)據(jù) √可以以字節(jié)(8位)為單位讀取,也可以以半字(16位)或者全字(32位)讀取 √每個(gè)芯片編碼是唯一的,出廠時(shí)固化,不可修改 √ 可用于產(chǎn)品序列號(hào) √用來(lái)作為密碼,提高安全性 √用來(lái)保護(hù)程序的不可復(fù)制
?
文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-637298.html
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-637298.html
main.c
#include "stm32f10x.h" //STM32頭文件 #include "sys.h" #include "delay.h" #include "relay.h" #include "oled0561.h" #include "led.h" #include "key.h" #include "usart.h" int main (void){//主程序 u32 ID[3]; delay_ms(500); //上電時(shí)等待其他器件就緒 RCC_Configuration(); //系統(tǒng)時(shí)鐘初始化 RELAY_Init();//繼電器初始化 LED_Init();//LED KEY_Init();//KEY USART1_Init(115200); //串口初始化(參數(shù)是波特率) I2C_Configuration();//I2C初始化 OLED0561_Init(); //OLED初始化---------------" OLED_DISPLAY_8x16_BUFFER(0," CHIP ID TEST "); //顯示字符串 ID[0] = *(__IO u32 *)(0X1FFFF7E8); //讀出3個(gè)32位ID 高字節(jié) ID[1] = *(__IO u32 *)(0X1FFFF7EC); // ID[2] = *(__IO u32 *)(0X1FFFF7F0); // 低字節(jié) //08表示后面的數(shù)據(jù)不足8位就補(bǔ)0顯示 printf("ChipID: %08X %08X %8X \r\n",ID[0],ID[1],ID[2]); //從串口輸出16進(jìn)制ID if(ID[0]==0x066EFF34 && ID[1]==0x3437534D && ID[2]==0x43232328){ //檢查ID是否匹配 printf("chipID OK! \r\n"); //匹配 }else{ printf("chipID error! \r\n"); //不同 } while(1){ } }
五:還需要補(bǔ)充的知識(shí)
1.仿真 仿真接口有JTAG、SW接口,仿真器又有ST-LINK、J-LINK等 還有純軟件仿真Proteus等 2.HEL庫(kù) 3.內(nèi)置USB接口 USB鼠標(biāo)、鍵盤(pán)、U盤(pán) 4.顯示屏 除OLED之外,還能外擴(kuò)LCD1602、12864等 顯示屏的類型還有VOG屏、TFT屏等 每種屏的接口也分好多種 5.定時(shí)器的復(fù)雜功能 TIM1高級(jí)定時(shí)器的使用 單脈沖模式 輸出比較器的使用 捕獲器的使用 定時(shí)器的DMA設(shè)置 6.中斷的復(fù)雜功能 中斷嵌套應(yīng)用與優(yōu)先級(jí)問(wèn)題 外部中斷的端口映射問(wèn)題 7.單片機(jī)內(nèi)部功能 WIFI、藍(lán)牙、GPS模塊、2.4G模塊、彩屏的人機(jī)界面、RTOS嵌入式操作系統(tǒng)....
到了這里,關(guān)于STM32基礎(chǔ)入門(mén)學(xué)習(xí)筆記:內(nèi)部高級(jí)功能應(yīng)用的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!