日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

STM32F103系列单片机学习笔记1方便以后查看

發(fā)布時間:2025/3/15 编程问答 14 豆豆
生活随笔 收集整理的這篇文章主要介紹了 STM32F103系列单片机学习笔记1方便以后查看 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
系統(tǒng)中斷管理:NVIC 我的理解——管理系統(tǒng)內(nèi)部的中斷,負(fù)責(zé)打開和關(guān)閉中斷。 基礎(chǔ)應(yīng)用 1,中斷的初始化函數(shù),包括設(shè)置中斷向量表位置,和開啟所需的中斷兩部分。所 有程序中必須的。 用法: void NVIC_Configuration(void) { NVIC_InitTypeDef NVIC_InitStructure;//中斷管理恢復(fù)默認(rèn)參數(shù) #ifdef VECT_TAB_RAM //如果 C/C++ Compiler\Preprocessor\Defined symbols 中的定義了 VECT_TAB_RAM(見程序庫 更改內(nèi)容的表格) NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0); //則在 RAM 調(diào)試 #else //如果沒有定義 VECT_TAB_RAM NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);//則在 Flash 里調(diào)試 #endif //結(jié)束判斷語句 //以下為中斷的開啟過程,不是所有程序必須的。 //NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //設(shè)置 NVIC 優(yōu)先級分組,方式。 //注:一共 16 個優(yōu)先級,分為搶占式和響應(yīng)式。兩種優(yōu)先級所占的數(shù)量由此代碼確定, NVIC_PriorityGroup_x 可以是 0、1、2、3、4,分別代表搶占優(yōu)先級有 1、2、4、816 個和 響應(yīng)優(yōu)先級有 16、842、1 個。規(guī)定兩種優(yōu)先級的數(shù)量后,所有的中斷級別必須在其中 選擇,搶占級別高的會打斷其他中斷優(yōu)先執(zhí)行,而響應(yīng)級別高的會在其他中斷執(zhí)行完優(yōu)先執(zhí) 行。 //NVIC_InitStructure.NVIC_IRQChannel = 中斷通道名; //開中斷,中斷名稱見函數(shù)庫 //NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //搶占優(yōu)先級 //NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //響應(yīng)優(yōu)先級 //NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//啟動此通道的中斷 //NVIC_Init(&NVIC_InitStructure); //中斷初始化 } 閱讀 rcc:單片機時鐘管理。 我的理解——管理外部、內(nèi)部和外設(shè)的時鐘,設(shè)置、打開和關(guān)閉這些時鐘。 基礎(chǔ)應(yīng)用 1:時鐘的初始化函數(shù)過程—— 用法:void RCC_Configuration(void) //時鐘初始化函數(shù) { ErrorStatus HSEStartUpStatus; //等待時鐘的穩(wěn)定 RCC_DeInit(); //時鐘管理重置 RCC_HSEConfig(RCC_HSE_ON); //打開外部晶振 HSEStartUpStatus = RCC_WaitForHSEStartUp(); //等待外部晶振就緒 if (HSEStartUpStatus == SUCCESS) { FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); //flash 讀取緩沖,加速 FLASH_SetLatency(FLASH_Latency_2); //flash 操作的延時 RCC_HCLKConfig(RCC_SYSCLK_Div1); //AHB 使用系統(tǒng)時鐘 RCC_PCLK2Config(RCC_HCLK_Div2); //APB2(高速)為 HCLK 的一半 RCC_PCLK1Config(RCC_HCLK_Div2); //APB1(低速)為 HCLK 的一半 //注:AHB 主要負(fù)責(zé)外部存儲器時鐘。PB2 負(fù)責(zé) AD,I/O,高級 TIM,串口 1。APB1 負(fù)責(zé) DA, USB,SPI,I2C,CAN,串口 2345,普通 TIM。 RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); //PLLCLK = 8MHz * 9 = 72 MHz RCC_PLLCmd(ENABLE); //啟動 PLL while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET){} //等待 PLL 啟動 RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //將 PLL 設(shè)置為系統(tǒng)時鐘源 while (RCC_GetSYSCLKSource() != 0x08){} //等待系統(tǒng)時鐘源的啟動 } //RCC_AHBPeriphClockCmd(ABP2 設(shè)備 1 | ABP2 設(shè)備 2 |, ENABLE); //啟動 AHP 設(shè)備 //RCC_APB2PeriphClockCmd(ABP2 設(shè)備 1 | ABP2 設(shè)備 2 |, ENABLE); //啟動 ABP2 設(shè)備 //RCC_APB1PeriphClockCmd(ABP2 設(shè)備 1 | ABP2 設(shè)備 2 |, ENABLE); //啟動 ABP1 設(shè)備 } 1、閱讀 exti:外部設(shè)備中斷函數(shù) 我的理解——外部設(shè)備通過引腳給出的硬件中斷,也可以產(chǎn)生軟件中斷,19 個上升、下降 或都觸發(fā)。EXTI0~EXTI15 連接到管腳,EXTI 線 16 連接到 PVD(VDD 監(jiān)視) ,EXTI 線 17 連接 到 RTC(鬧鐘),EXTI 線 18 連接到 USB(喚醒)。 基礎(chǔ)應(yīng)用 1,設(shè)定外部中斷初始化函數(shù)。按需求,不是必須代碼。 用法: void EXTI_Configuration(void) { EXTI_InitTypeDef EXTI_InitStructure; //外部設(shè)備中斷恢復(fù)默認(rèn)參數(shù) EXTI_InitStructure.EXTI_Line = 通道 1|通道 2; //設(shè)定所需產(chǎn)生外部中斷的通道,一共 19 個。 EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //產(chǎn)生中斷 EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //上升下降沿都觸發(fā) EXTI_InitStructure.EXTI_LineCmd = ENABLE; //啟動中斷的接收 EXTI_Init(&EXTI_InitStructure); //外部設(shè)備中斷啟動 } 2、閱讀 dma:通過總線而越過 CPU 讀取外設(shè)數(shù)據(jù) 我的理解——通過 DMA 應(yīng)用可以加速單片機外設(shè)、存儲器之間的數(shù)據(jù)傳輸,并在傳輸期間 不影響 CPU 進行其他事情。這對于入門開發(fā)基本功能來說沒有太大必要,這個內(nèi)容先行跳 過。 3、閱讀 systic:系統(tǒng)定時器 我的理解——可以輸出和利用系統(tǒng)時鐘的計數(shù)、狀態(tài)。 基礎(chǔ)應(yīng)用 1,精確計時的延時子函數(shù)。推薦使用的代碼。 用法: static vu32 TimingDelay;//全局變量聲明 void SysTick_Config(void)//systick 初始化函數(shù) { SysTick_CounterCmd(SysTick_Counter_Disable);//停止系統(tǒng)定時器 SysTick_ITConfig(DISABLE); //停止 systick 中斷 SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //systick 使用 HCLK 作為時鐘源,頻率值除以 8。 SysTick_SetReload(9000);//重置時間 1 毫秒(以 72MHz 為基礎(chǔ)計算) SysTick_ITConfig(ENABLE);//開啟 systic 中斷 } void Delay (u32 nTime) //延遲一毫秒的函數(shù) { SysTick_CounterCmd(SysTick_Counter_Enable); //systic 開始計時 TimingDelay = nTime; //計時長度賦值給遞減變量 while(TimingDelay != 0); //檢測是否計時完成 SysTick_CounterCmd(SysTick_Counter_Disable); //關(guān)閉計數(shù)器 SysTick_CounterCmd(SysTick_Counter_Clear); //清除計數(shù)值 } void TimingDelay_Decrement(void) //遞減變量函數(shù),函數(shù)名由“stm32f10x_it.c”中的中斷響應(yīng)函數(shù)定義好了。 { if (TimingDelay != 0x00) //檢測計數(shù)變量是否達到 0 { TimingDelay‐‐; //計數(shù)變量遞減 } } 注:建議熟練后使用,所涉及知識和設(shè)備太多,新手出錯的可能性比較大。新手可用簡化的 延時函數(shù)代替: void Delay(vu32 nCount)//簡單延時函數(shù) { for(; nCount != 0; nCount‐‐);(循環(huán)變量遞減計數(shù)) } 當(dāng)延時較長,又不需要精確計時的時候可以使用嵌套循環(huán): void Delay(vu32 nCount) //簡單的長時間延時函數(shù) {int i; //聲明內(nèi)部遞減變量 for(; nCount != 0; nCount‐‐) //遞減變量計數(shù) {for (i=0; i<0xffff; i++)} //內(nèi)部循環(huán)遞減變量計數(shù) } 4、閱讀 gpio:I/O 設(shè)置函數(shù) 我的理解——所有輸入輸出管腳模式設(shè)置,可以是上下拉、浮空、開漏、模擬、推挽模式, 頻率特性為 2M,10M,50M。也可以向該管腳直接寫入數(shù)據(jù)和讀取數(shù)據(jù)。 基礎(chǔ)應(yīng)用 1,gpio 初始化函數(shù)。所有程序必須。 用法:void GPIO_Configuration(void) { GPIO_InitTypeDef GPIO_InitStructure; //GPIO 狀態(tài)恢復(fù)默認(rèn)參數(shù) GPIO_InitStructure.GPIO_Pin = GPIO_Pin_標(biāo)號 | GPIO_Pin_標(biāo)號 ; //管腳位置定義,標(biāo)號可以是 NONE、ALL、0 至 15。 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;//輸出速度 2MHz GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模擬輸入模式 GPIO_Init(GPIOC, &GPIO_InitStructure); //C 組 GPIO 初始化 //注:以上四行代碼為一組,每組 GPIO 屬性必須相同,默認(rèn)的 GPIO 參數(shù)為:ALL,2MHz, FLATING。如果其中任意一行與前一組相應(yīng)設(shè)置相同,那么那一行可以省略,由此推論如果 前面已經(jīng)將此行參數(shù)設(shè)定為默認(rèn)參數(shù)(包括使用 GPIO_InitTypeDef GPIO_InitStructure 代碼), 本組應(yīng)用也是默認(rèn)參數(shù)的話,那么也可以省略。以下重復(fù)這個過程直到所有應(yīng)用的管腳全部 被定義完畢。 ...... } 基礎(chǔ)應(yīng)用 2,向管腳寫入 01 用法:GPIO_WriteBit(GPIOB, GPIO_Pin_2, (BitAction)0x01);//寫入 1 sw 笨笨的 STM32 筆記之七:讓它跑起來,基本硬件 功能的建立 SW笨笨 發(fā)表于 2009022709:00 閱讀(46) 評論(0) 分類: 個人日記 舉報 0、 實驗之前的準(zhǔn)備 a) 接通串口轉(zhuǎn)接器 b) 下載 IO 與串口的原廠程序,編譯通過保證調(diào)試所需硬件正常。 1、 flash,lib,nvic,rcc 和 GPIO,基礎(chǔ)程序庫編寫 a) 這幾個庫函數(shù)中有一些函數(shù)是關(guān)于芯片的初始化的,每個程序中必用。為保障程序品 質(zhì),初學(xué)階段要求嚴(yán)格遵守官方習(xí)慣。注意,官方程序庫例程中有個 platform_config.h 文件, 是專門用來指定同類外設(shè)中第幾號外設(shè)被使用,就是說在 main.c 里面所有外設(shè)序號用 x 代 替,比如 USARTx,程序會到這個頭文件中去查找到底是用那些外設(shè),初學(xué)的時候參考例程 別被這個所迷惑住。 b) 全部必用代碼取自庫函數(shù)所帶例程,并增加逐句注釋。 c) 習(xí)慣順序——Lib(debug),RCC(包括 Flash 優(yōu)化),NVIC,GPIO d) 必用模塊初始化函數(shù)的定義: void RCC_Configuration(void); //定義時鐘初始化函數(shù) void GPIO_Configuration(void); //定義管腳初始化函數(shù) void NVIC_Configuration(void); //定義中斷管理初始化函數(shù) void Delay(vu32 nCount); //定義延遲函數(shù) e) Main 中的初始化函數(shù)調(diào)用: RCC_Configuration(); //時鐘初始化函數(shù)調(diào)用 NVIC_Configuration(); //中斷初始化函數(shù)調(diào)用 GPIO_Configuration(); //管腳初始化函數(shù)調(diào)用 f) Lib 注意事項: 屬于 Lib 的 Debug 函數(shù)的調(diào)用,應(yīng)該放在 main 函數(shù)最開始,不要改變其位置。 g) RCC 注意事項: Flash 優(yōu)化處理可以不做,但是兩句也不難也不用改參數(shù)...... 根據(jù)需要開啟設(shè)備時鐘可以節(jié)省電能 時鐘頻率需要根據(jù)實際情況設(shè)置參數(shù) h) NVIC 注意事項 注意理解占先優(yōu)先級和響應(yīng)優(yōu)先級的分組的概念 i) GPIO 注意事項 注意以后的過程中收集不同管腳應(yīng)用對應(yīng)的頻率和模式的設(shè)置。 作為高低電平的 I/O,所需設(shè)置:RCC 初始化里面打開 RCC_APB2 PeriphClockCmd(RCC_APB2Periph_GPIOA);GPIO 里面管腳設(shè)定:IO 輸出(50MHz,Out_PP); IO 輸入(50MHz,IPU); j) GPIO 應(yīng)用 GPIO_WriteBit(GPIOB, GPIO_Pin_2, Bit_RESET);//重置 GPIO_WriteBit(GPIOB, GPIO_Pin_2, (BitAction)0x01);//寫入 1 GPIO_WriteBit(GPIOB, GPIO_Pin_2, (BitAction)0x00);//寫入 0 GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6) ;//讀入 IO k) 簡單 Delay 函數(shù) void Delay(vu32 nCount)//簡單延時函數(shù) {for(; nCount != 0; nCount‐‐);} 實驗步驟: RCC 初 始 化 函 數(shù) 里 添 加 : RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB , ENABLE); 不用其他中斷,NVIC 初始化函數(shù)不用改 GPIO 初始化代碼: //IO 輸入,GPIOB 的 2、10、11 腳輸出 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 ;//管腳號 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //輸出速度 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //輸入輸出模式 GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化 簡單的延遲函數(shù): void Delay(vu32 nCount) //簡單延時函數(shù) { for (; nCount != 0; nCount‐‐);} //循環(huán)計數(shù)延時 完成之后再在 main.c 的 while 里面寫一段: GPIO_WriteBit(GPIOB, GPIO_Pin_2, (BitAction)0x01);//寫入 1 Delay(0xffff); GPIO_WriteBit(GPIOB, GPIO_Pin_2, (BitAction)0x00);//寫入 0 Delay(0xffff); 就可以看到連接在 PB2 腳上的 LED 閃爍了,單片機就跑起來了。 sw 笨笨的 STM32 筆記之八:來跟 PC 打個招呼,基本串口通訊 a) 目的:在基礎(chǔ)實驗成功的基礎(chǔ)上,對串口的調(diào)試方法進行實踐。硬件代碼順利完成之 后,對日后調(diào)試需要用到的 printf 重定義進行調(diào)試,固定在自己的庫函數(shù)中。 b) 初始化函數(shù)定義: void USART_Configuration(void); //定義串口初始化函數(shù) c) 初始化函數(shù)調(diào)用: void UART_Configuration(void); //串口初始化函數(shù)調(diào)用 初始化代碼: void USART_Configuration(void) //串口初始化函數(shù) { //串口參數(shù)初始化 USART_InitTypeDef USART_InitStructure; //串口設(shè)置恢復(fù)默認(rèn)參數(shù) //初始化參數(shù)設(shè)置 USART_InitStructure.USART_BaudRate = 9600; //波特率 9600 USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字長 8 位 USART_InitStructure.USART_StopBits = USART_StopBits_1; //1 位停止字節(jié) USART_InitStructure.USART_Parity = USART_Parity_No; //無奇偶校驗 USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//無 流控制 USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//打開 Rx 接收和 T x 發(fā)送功能 USART_Init(USART1, &USART_InitStructure); //初始化 USART_Cmd(USART1, ENABLE); //啟動串口 } RCC 中打開相應(yīng)串口 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 , ENABLE); GPIO 里面設(shè)定相應(yīng)串口管腳模式 //串口 1 的管腳初始化 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //管腳 9 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //復(fù)用推挽輸出 GPIO_Init(GPIOA, &GPIO_InitStructure); //TX 初始化 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //管腳 10 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空輸入 GPIO_Init(GPIOA, &GPIO_InitStructure); //RX 初始化 d) 簡單應(yīng)用: 發(fā)送一位字符 USART_SendData(USART1, 數(shù)據(jù)); //發(fā)送一位數(shù)據(jù) while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET) {} //等待發(fā)送完畢 接收一位字符 while(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET) {} //等待接收完畢 變量= (USART_ReceiveData(USART1)); //接受一個字節(jié) 發(fā)送一個字符串 先定義字符串:char rx_data[250]; 然后在需要發(fā)送的地方添加如下代碼 int i; //定義循環(huán)變量 while(rx_data!='\0') // 循環(huán)逐字輸出,到結(jié)束字 '\0' {USART_SendData(USART1, rx_data); // 發(fā)送字符 while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET){} // 等待字符發(fā)送完畢 i++;} e) USART 注意事項: 發(fā)動和接受都需要配合標(biāo)志等待。 只能對一個字節(jié)操作,對字符串等大量數(shù)據(jù)操作需要寫函數(shù) 使用串口所需設(shè)置: RCC 初始化里面打開 RCC_APB2PeriphClockCmd (RCC_APB2Periph_USARTx);GPIO 里面管腳設(shè)定:串口 RX ( 50Hz , IN_FLOATING );串口 TX ( 5 0Hz , AF_PP ); f) printf 函數(shù)重定義(不必理解,調(diào)試通過以備后用) ( 1 ) 需要 c 標(biāo)準(zhǔn)函數(shù): #include "stdio.h" ( 2 ) 粘貼函數(shù)定義代碼 #define PUTCHAR_PROTOTYPE int __io_putchar(int ch) // 定義為 putchar 應(yīng)用 ( 3 ) RCC 中打開相應(yīng)串口 ( 4 ) GPIO 里面設(shè)定相應(yīng)串口管腳模式 ( 6 ) 增加為 putchar 函數(shù)。 int putchar(int c) //putchar 函數(shù) { if (c == '\n'){putchar('\r');} // 將 printf 的 \n 變成 \r USART_SendData(USART1, c); // 發(fā)送字符 while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET){} // 等待發(fā)送結(jié)束 return c; // 返回值 } ( 8 ) 通過,試驗成功。 printf 使用變量輸出 :%c 字符, %d 整數(shù), %f 浮點數(shù) ,%s 字符串, /n 或 /r 為換行。注意:只能用于 main.c 中。 3 、 NVIC 串口中斷的應(yīng)用 a) 目的:利用前面調(diào)通的硬件基礎(chǔ),和幾個函數(shù)的代碼,進行串口的中斷輸入練習(xí)。因 為在實際應(yīng)用中,不使用中斷進行的輸入是效率非常低的,這種用法很少見,大部分串口的 輸入都離不開中斷。 b) 初始化函數(shù)定義及函數(shù)調(diào)用:不用添加和調(diào)用初始化函數(shù),在指定調(diào)試地址的時候已 經(jīng)調(diào)用過,在那個 NVIC_Configuration 里面添加相應(yīng)開中斷代碼就行了。 c) 過程: i. 在串口初始化中 USART_Cmd 之前加入中斷設(shè)置: USART_ITConfig(USART1, USART_IT_TXE, ENABLE);//TXE 發(fā)送中斷, TC 傳輸完成中斷, RXNE 接收中斷, PE 奇偶錯誤中斷,可以是多個。 ii. RCC 、 GPIO 里面打開串口相應(yīng)的基本時鐘、管腳設(shè)置 iii. NVIC 里面加入串口中斷打開代碼: NVIC_InitTypeDef NVIC_InitStructure;// 中斷默認(rèn)參數(shù) NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQChannel;// 通道設(shè)置為串口 1 中斷 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // 中斷占先等級 0 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; // 中斷響應(yīng)優(yōu)先級 0 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 打開中斷 NVIC_Init(&NVIC_InitStructure); // 初始化 iv. 在 stm32f10x_it.c 文件中找到 void USART1_IRQHandler 函數(shù),在其中添入執(zhí)行代碼。 一般最少三個步驟:先使用 if 語句判斷是發(fā)生那個中斷,然后清除中斷標(biāo)志位,最后給字符 串賦值,或做其他事情。 void USART1_IRQHandler(void) // 串口 1 中斷 { char RX_dat; // 定義字符變量 if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) // 判斷發(fā)生接收中斷 {USART_ClearITPendingBit(USART1, USART_IT_RXNE); // 清除中斷標(biāo)志 GPIO_WriteBit(GPIOB, GPIO_Pin_10, (BitAction)0x01); // 開始傳輸 RX_dat=USART_ReceiveData(USART1) & 0x7F; // 接收數(shù)據(jù),整理除去前兩位 USART_SendData(USART1, RX_dat); // 發(fā)送數(shù)據(jù) while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET){}// 等待發(fā)送結(jié)束 } } d) 中斷注意事項: 可以隨時在程序中使用 USART_ITConfig(USART1, USART_IT_TXE, DISABLE); 來關(guān)閉中斷響應(yīng)。 NVIC_InitTypeDef NVIC_InitStructure 定義一定要加在 NVIC 初始化模塊的第一句。 全局變量與函數(shù)的定義:在任意 .c 文件中定義的變量或函數(shù),在其它 .c 文件中使用 extern+ 定義代碼再次定義就可以直接調(diào)用了。 sw 笨笨的 STM32 筆記之九:打斷它來為我辦事,EXI T (外部 I/O 中斷)應(yīng)用 a) 目的:跟串口輸入類似,不使用中斷進行的 IO 輸入效率也很低,而且可以通過 E XTI 插入按鈕事件,本節(jié)聯(lián)系 EXTI 中斷。 b) 初始化函數(shù)定義: void EXTI_Configuration(void); //定義 IO 中斷初始化函數(shù) c) 初始化函數(shù)調(diào)用: EXTI_Configuration();//IO 中斷初始化函數(shù)調(diào)用簡單應(yīng)用: d) 初始化函數(shù): void EXTI_Configuration(void) { EXTI_InitTypeDef EXTI_InitStructure; //EXTI 初始化結(jié)構(gòu)定義 EXTI_ClearITPendingBit(EXTI_LINE_KEY_BUTTON);//清除中斷標(biāo)志 GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource3);//管腳選擇 GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource4); GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource5); GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource6); EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//事件選擇 EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//觸發(fā)模式 EXTI_InitStructure.EXTI_Line = EXTI_Line3 | EXTI_Line4; //線路選擇 EXTI_InitStructure.EXTI_LineCmd = ENABLE;//啟動中斷 EXTI_Init(&EXTI_InitStructure);//初始化 } e) RCC 初始化函數(shù)中開啟 I/O 時鐘 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE); GPIO 初始化函數(shù)中定義輸入 I/O 管腳。 //IO 輸入,GPIOA 的 4 腳輸入 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉輸入 GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化 f) 在 NVIC 的初始化函數(shù)里面增加以下代碼打開相關(guān)中斷: NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQChannel; //通道 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//占先級 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //響應(yīng)級 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //啟動 NVIC_Init(&NVIC_InitStructure); //初始化 g) 在 stm32f10x_it.c 文件中找到 void USART1_IRQHandler 函數(shù),在其中添入執(zhí)行代 碼。一般最少三個步驟:先使用 if 語句判斷是發(fā)生那個中斷,然后清除中斷標(biāo)志位,最后給 字符串賦值,或做其他事情。 if(EXTI_GetITStatus(EXTI_Line3) != RESET) //判斷中 斷發(fā)生來源 { EXTI_ClearITPendingBit(EXTI_Line3); // 清除中斷標(biāo)志 USART_SendData(USART1, 0x41); / /發(fā)送字符“a” GPIO_WriteBit(GPIOB, GPIO_Pin_2, (BitAction)(1‐GPIO_ReadOutputDataBit(GPIOB, GPIO_ Pin_2)));//LED 發(fā)生明暗交替 } h) 中斷注意事項: 中斷發(fā)生后必須清除中斷位,否則會出現(xiàn)死循環(huán)不斷發(fā)生這個中斷。然后需要對中斷類型進 行判斷再執(zhí)行代碼。 使用 EXTI 的 I/O 中斷,在完成 RCC 與 GPIO 硬件設(shè)置之后需要做三件事:初始化 EXTI、NVIC 開中斷、編寫中斷執(zhí)行代碼。 sw 笨笨的 STM32 筆記之十:工作工作,PWM 輸出 a) 目的:基礎(chǔ) PWM 輸出,以及中斷配合應(yīng)用。輸出選用 PB1,配置為 TIM3_CH4, 是目標(biāo)板的 LED6 控制腳。 b) 對于簡單的 PWM 輸出應(yīng)用,暫時無需考慮 TIM1 的高級功能之區(qū)別。 c) 初始化函數(shù)定義: void TIM_Configuration(void); //定義 TIM 初始化函數(shù) d) 初始化函數(shù)調(diào)用: TIM_Configuration(); //TIM 初始化函數(shù)調(diào)用 e) 初始化函數(shù),不同于前面模塊,TIM 的初始化分為兩部分——基本初始化和通道 初始化: void TIM_Configuration(void)//TIM 初始化函數(shù) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;//定時器初始化結(jié)構(gòu) TIM_OCInitTypeDef TIM_OCInitStructure;//通道輸出初始化結(jié)構(gòu) //TIM3 初始化 TIM_TimeBaseStructure.TIM_Period = 0xFFFF; //周期 0~FFFF TIM_TimeBaseStructure.TIM_Prescaler = 5; //時鐘分頻 TIM_TimeBaseStructure.TIM_ClockDivision = 0; //時鐘分割 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//模式 TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //基本初始化 TIM_ITConfig(TIM3, TIM_IT_CC4, ENABLE);//打開中斷,中斷需要這行代碼 //TIM3 通道初始化 TIM_OCStructInit(& TIM_OCInitStructure); //默認(rèn)參數(shù) TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //工作 狀態(tài) TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //設(shè)定為輸出, 需要 PWM 輸出才需要這行代碼 TIM_OCInitStructure.TIM_Pulse = 0x2000; //占空長 度 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //高電平 TIM_OC4Init(TIM3, &TIM_OCInitStructure); //通道初 始化 TIM_Cmd(TIM3, ENABLE); //啟動 TIM3 } f) RCC 初始化函數(shù)中加入 TIM 時鐘開啟: RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM3, ENABLE); g) GPIO 里面將輸入和輸出管腳模式進行設(shè)置。信號:AF_PP,50MHz。 h) 使用中斷的話在 NVIC 里添加如下代碼: //打開 TIM2 中斷 NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQChannel; //通道 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;//占先級 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //響應(yīng)級 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //啟動 NVIC_Init(&NVIC_InitStructure); //初始 化 中斷代碼: void TIM2_IRQHandler(void) { if (TIM_GetITStatus(TIM2, TIM_IT_CC4) != RESET) //判斷中斷來源 { TIM_ClearITPendingBit(TIM2, TIM_IT_CC4); //清除中斷標(biāo)志 GPIO_WriteBit(GPIOB, GPIO_Pin_11, (BitAction)(1‐GPIO_ReadOutputDataBit(GPIOB, GPIO _Pin_11)));//變換 LED 色彩 IC4value = TIM_GetCapture4(TIM2); //獲取捕捉數(shù)值 } } i) 簡單應(yīng)用: //改變占空比 TIM_SetCompare4(TIM3, 變量); j) 注意事項: 管腳的 IO 輸出模式是根據(jù)應(yīng)用來定,比如如果用 PWM 輸出驅(qū)動 LED 則應(yīng)該將相應(yīng)管腳設(shè) 為 AF_PP,否則單片機沒有輸出。 sw 笨笨的 STM32 筆記之十一:捕捉精彩瞬間,脈沖方波長度捕獲 a) 目的:基礎(chǔ) PWM 輸入也叫捕獲,以及中斷配合應(yīng)用。使用前一章的輸出管腳 P B1(19 腳),直接使用跳線連接輸入的 PA3(13 腳),配置為 TIM2_CH4,進行實驗。 b) 對于簡單的 PWM 輸入應(yīng)用,暫時無需考慮 TIM1 的高級功能之區(qū)別,按照目前 我的應(yīng)用目標(biāo)其實只需要采集高電平寬度,而不必知道周期,所以并不采用 PWM 輸入模式, 而是普通脈寬捕獲模式。 c) 初始化函數(shù)定義: void TIM_Configuration(void); //定義 TIM 初始化函數(shù) d) 初始化函數(shù)調(diào)用: TIM_Configuration(); //TIM 初始化函數(shù)調(diào)用 e) 初始化函數(shù),不同于前面模塊,TIM 的 CAP 初始化分為三部分——計時器基本初 始化、通道初始化和時鐘啟動初始化: void TIM_Configuration(void)//TIM2 的 CAP 初始化函數(shù) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;//定時器初始化結(jié)構(gòu) TIM_ICInitTypeDef TIM_ICInitStructure; //通道輸入初始化結(jié)構(gòu) //TIM2 輸出初始化 TIM_TimeBaseStructure.TIM_Period = 0xFFFF; //周期 0~FFFF TIM_TimeBaseStructure.TIM_Prescaler = 5; //時鐘分頻 TIM_TimeBaseStructure.TIM_ClockDivision = 0; //時鐘分割 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//模式 TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);//基本初始化 //TIM2 通道的捕捉初始化 TIM_ICInitStructure.TIM_Channel = TIM_Channel_4;//通道選擇 TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling;//下降沿 TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;//管腳與寄存器對應(yīng)關(guān)系 TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;//分頻器 TIM_ICInitStructure.TIM_ICFilter = 0x4; //濾波設(shè)置,經(jīng)歷幾個周期跳變認(rèn)定波形 穩(wěn)定 0x0~0xF TIM_ICInit(TIM2, &TIM_ICInitStructure); //初始化 TIM_SelectInputTrigger(TIM2, TIM_TS_TI2FP2); //選擇時鐘觸發(fā)源 TIM_SelectSlaveMode(TIM2, TIM_SlaveMode_Reset);//觸發(fā)方式 TIM_SelectMasterSlaveMode(TIM2, TIM_MasterSlaveMode_Enable); //啟動定時器的被動 觸發(fā) TIM_ITConfig(TIM2, TIM_IT_CC4, ENABLE); //打開中斷 TIM_Cmd(TIM2, ENABLE); //啟動 TIM2 } f) RCC 初始化函數(shù)中加入 TIM 時鐘開啟: RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM3, ENABLE); g) GPIO 里面將輸入和輸出管腳模式進行設(shè)置。IN_FLOATING,50MHz。 h) 使用中斷的話在 NVIC 里添加如下代碼: //打開 TIM 中斷(與前一章相同) NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQChannel; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; i) 簡單應(yīng)用: 變量 = TIM_GetCapture4(TIM2); j) 注意事項: i. 由于我的需求只跟高電平寬度有關(guān),所以避免了使用 PWM 輸入模式,這樣可以 每個管腳捕捉一路信號。如果使用 PWM 模式,每一路需要占用兩個寄存器,所以一個定時 器只能同時使用兩路 PWM 輸入。 ii. 由于捕捉需要觸發(fā)啟動定時器,所以 PWM 輸出與捕捉不容易在同一個 TIM 通道 上實現(xiàn)。如果必須的話只能增加計數(shù)溢出的相關(guān)代碼。 iii. 有些程序省略了捕捉通道的初始化代碼,這是不對的 iv. 在基本計時器初始化代碼里面注意選擇適當(dāng)?shù)挠嫈?shù)器長度,最好讓波形長度不要 長于一個計數(shù)周期,否則需要增加溢出代碼很麻煩。一個計數(shù)周期的長度計算跟如下幾個參 數(shù)有關(guān): (1) RCC 初始化代碼里面的 RCC_PCLKxConfig,這是 TIM 的基礎(chǔ)時鐘源與系統(tǒng)時鐘 的關(guān)系。 (2) TIM 初始化的 TIM_Period,這是計數(shù)周期的值 (3) TIM 初始化的 TIM_Prescaler,這是計數(shù)周期的倍頻計數(shù)器,相當(dāng)于調(diào)節(jié)計數(shù) 周期,可以使 TIM_Period 盡量大,提高計數(shù)精度。 sw 笨笨的 STM32 筆記之十二:時鐘不息工作不止, systic 時鐘應(yīng)用 a) 目的:使用系統(tǒng)時鐘來進行兩項實驗——周期執(zhí)行代碼與精確定時延遲。 b) 初始化函數(shù)定義: void SysTick_Configuration(void); c) 初始化函數(shù)調(diào)用: SysTick_Configuration(); d) 初始化函數(shù): void SysTick_Configuration(void) { SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);//時鐘除 8 SysTick_SetReload(250000); // 計數(shù)周期長度 SysTick_CounterCmd(SysTick_Counter_Enable); //啟動計時器 SysTick_ITConfig(ENABLE); // 打開中斷 } e) 在 NVIC 的初始化函數(shù)里面增加以下代碼打開相關(guān)中斷: NVIC_SystemHandlerPriorityConfig(SystemHandler_SysTick, 1, 0);//中斷等級設(shè)置,一般設(shè)置的 高一些會少受其他影響 f) 在 stm32f10x_it.c 文件中找到 void SysTickHandler 函數(shù) void SysTickHandler(void) { 執(zhí)行代碼 } g) 簡單應(yīng)用:精確延遲函數(shù),因為 systic 中斷往往被用來執(zhí)行周期循環(huán)代碼,所以 一些例程中使用其中斷的啟動和禁止來編寫的精確延時函數(shù)實際上不實用,我自己編寫了精 確計時函數(shù)反而代碼更精簡,思路更簡單。思路是調(diào)用后,變量清零,然后使用時鐘來的曾 變量,不斷比較變量與延遲的數(shù)值,相等則退出函數(shù)。代碼和步驟如下: i. 定義通用變量:u16 Tic_Val=0; //變量用于精確計時 ii. 在 stm32f10x_it.c 文件中相應(yīng)定義: extern u16 Tic_Val;//在本文件引用 MAIN.c 定義的精確計時變量 iii. 定義函數(shù)名稱:void Tic_Delay(u16 Tic_Count);//精確延遲函數(shù) iv. 精確延時函數(shù): void Tic_Delay(u16 Tic_Count) //精確延時函數(shù) { Tic_Val=0; //變量清零 while(Tic_Val != Tic_Count){printf("");}//計時 } v. 在 stm32f10x_it.c 文件中 void SysTickHandler 函數(shù)里面添加 Tic_Val++;//變量遞增 vi. 調(diào)用代碼:Tic_Delay(10); //精確延時 疑問:如果去掉計時行那個沒用的 printf("");函數(shù)將停止工作,這個現(xiàn)象很奇 vii. 怪 sw 笨笨的 STM32 筆記之十三:惡搞,兩只看門狗 a) 目的: 了解兩種看門狗(我叫它:系統(tǒng)運行故障探測器和獨立系統(tǒng)故障探測器,新手往往被這個并 不形象的象形名稱搞糊涂)之間的區(qū)別和基本用法。 b) 相同: 都是用來探測系統(tǒng)故障,通過編寫代碼定時發(fā)送故障清零信號(高手們都管這個代碼叫做“喂 狗” ),告訴它系統(tǒng)運行正常。一旦系統(tǒng)故障,程序清零代碼( “喂狗” )無法執(zhí)行,其計數(shù)器就 會計數(shù)不止,直到記到零并發(fā)生故障中斷(狗餓了開始叫喚),控制 CPU 重啟整個系統(tǒng)(不 行啦,開始咬人了,快跑......)。 c) 區(qū)別: 獨立看門狗 Iwdg——我的理解是獨立于系統(tǒng)之外,因為有獨立時鐘,所以不受系統(tǒng)影響的系 統(tǒng)故障探測器。(這條狗是借來的,見誰偷懶它都咬!)主要用于監(jiān)視硬件錯誤。 窗口看門狗 wwdg——我的理解是系統(tǒng)內(nèi)部的故障探測器,時鐘與系統(tǒng)相同。如果系統(tǒng)時鐘 不走了,這個狗也就失去作用了。 (這條狗是老板娘養(yǎng)的,老板不干活兒他不管!)主要用于 監(jiān)視軟件錯誤。 d) 初始化函數(shù)定義:鑒于兩只狗作用差不多,使用過程也差不多初始化函數(shù)栓一起了, 用的時候根據(jù)情況刪減。 void WDG_Configuration(void); e) 初始化函數(shù)調(diào)用: WDG_Configuration(); f) 初始化函數(shù) void WDG_Configuration() //看門狗初始化 { //軟件看門狗初始化 WWDG_SetPrescaler(WWDG_Prescaler_8); //時鐘 8 分頻 4ms // (PCLK1/4096)/8= 244 Hz (~4 ms) WWDG_SetWindowValue(65); //計數(shù)器數(shù)值 WWDG_Enable(127); //啟動計數(shù)器,設(shè)置喂狗時間 // WWDG timeout = ~4 ms * 64 = 262 ms WWDG_ClearFlag(); //清除標(biāo)志位 WWDG_EnableIT(); //啟動中斷 //獨立看門狗初始化 IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);//啟動寄存器讀寫 IWDG_SetPrescaler(IWDG_Prescaler_32);//40K 時鐘 32 分頻 IWDG_SetReload(349); //計數(shù)器數(shù)值 IWDG_ReloadCounter(); //重啟計數(shù)器 IWDG_Enable(); //啟動看門狗 } g) RCC 初始化:只有軟件看門狗需要時鐘初始化,獨立看門狗有自己的時鐘不需要但是 需要 systic 工作相關(guān)設(shè)置。 RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); h) 獨立看門狗使用 systic 的中斷來喂狗,所以添加 systic 的中斷打開代碼就行了。軟件看 門狗需要在 NVIC 打開中斷添加如下代碼: NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQChannel; //通道 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //占先中斷等級 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //響應(yīng)中斷優(yōu)先級 NVIC_Init(&NVIC_InitStructure); //打開中斷 i) 中斷程序,軟件看門狗在自己的中斷中喂狗,獨立看門狗需要使用 systic 的定時中斷來 喂狗。以下兩個程序都在 stm32f10x_it.c 文件中。 void WWDG_IRQHandler(void) { WWDG_SetCounter(0x7F); //更新計數(shù)值 WWDG_ClearFlag(); //清除標(biāo)志位 } void SysTickHandler(void) { IWDG_ReloadCounter(); //重啟計數(shù)器(喂狗) } j) 注意事項: i. 有狗平常沒事情可以不理,但是千萬別忘了喂它,否則死都不知道怎么死的! ii. 初始化程序的調(diào)用一定要在 systic 的初始化之后。 iii. 獨立看門狗需要 systic 中斷來喂,但是 systic 做別的用處不能只做這件事,所以我寫 了如下幾句代碼,可以不影響 systic 的其他應(yīng)用,其他 systic 周期代碼也可參考: 第一步:在 stm32f10x_it.c 中定義變量 int Tic_IWDG; //喂狗循環(huán)程序的頻率判斷變量 第二步:將 SysTickHandler 中喂狗代碼改為下面: Tic_IWDG++; //變量遞增 if(Tic_IWDG>=100) //每 100 個 systic 周期喂狗 { IWDG_ReloadCounter();//重啟計數(shù)器(喂狗) Tic_IWDG=0; //變量清零 }

總結(jié)

以上是生活随笔為你收集整理的STM32F103系列单片机学习笔记1方便以后查看的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。