嵌入式學(xué)習(xí)
第一章 什么是嵌入式系統(tǒng)
1. 計(jì)算機(jī)的體系架構(gòu)
-
馮諾依曼架構(gòu)
? 在完整的計(jì)算機(jī)系統(tǒng)中,包含五個(gè)部分,儲(chǔ)存器,運(yùn)算器,控制器輸入設(shè)備和輸出設(shè)備。
改進(jìn)的馮諾依曼架構(gòu)
改進(jìn)型架構(gòu)的各模塊的高速數(shù)據(jù)交換中心利用儲(chǔ)存器這個(gè)大容量,極大的提高了效率。
-
哈佛架構(gòu)
? 哈佛結(jié)構(gòu)數(shù)據(jù)空間和地址空間是分開的。
-
兩者的比較
? 兩者的區(qū)別就是程序空間和 數(shù)據(jù)空間是否一體的。馮諾依曼數(shù)據(jù)結(jié)構(gòu)和地址分不開,哈佛結(jié)構(gòu)數(shù)據(jù)空間和地址空間是分開的。
第二章ARM系列內(nèi)核
2.1 什么是ARM
? ARM是一家公司,只做CPU設(shè)計(jì),采用出售IP的方式運(yùn)行,半導(dǎo)體制造商,ARM同時(shí)是一種架構(gòu),一種結(jié)構(gòu)體系,最新為ARM Cortex架構(gòu)。
ARM體系結(jié)構(gòu)特點(diǎn)
- 體積小,低功耗、成本低、高性能
- 支持Thumb(16位)與ARM(32位)雙指令集,有良好的兼容性。
- 大量使用寄存器,執(zhí)行速度快,數(shù)據(jù)操作在寄存器中完成,
- 共有37個(gè)寄存器,有7種不同的處理模式
- 尋址方式靈活簡單,指令長度固定,執(zhí)行效率高。
2.2 ARM指令集與Thumb指令集
- ARM指令集特點(diǎn):
為典型的精簡指令集。固定32位指令寬度,指令結(jié)構(gòu)十分規(guī)整,便于存儲(chǔ),傳輸,解析和執(zhí)行。自ARM7開始加入了Thumb指令集。 - Thumb指令集特點(diǎn):
Thumb指令集是精簡的16位指令集。只能完成32位標(biāo)準(zhǔn)ARM大部分功能,但是它的16位設(shè)計(jì)可以有效減少二進(jìn)制代碼的大小,降低對存儲(chǔ)器容量的要求,而降低成本。但使得整個(gè)CPU更加負(fù)載,尤其是開發(fā)人員必須謹(jǐn)慎處理兩類指令集模式的切換。
2.3 Cortex-M3處理器架構(gòu)
Thumb2指令集特點(diǎn):
? Thumb2在前面兩者之間取了一個(gè)平衡,兼有二者的優(yōu)勢, 當(dāng)一個(gè)操作可以使用一條 32位指令完成時(shí)就使用 32位的指令,加快運(yùn)行速度,而當(dāng)一次操作只需要一條16位指令完成時(shí),就使用16位的指令,節(jié)約存儲(chǔ)空間。
2.4 STM32F103系列微控制器
? 命名法則:
? 芯片選型:(夠用即可)
? STM32性能與結(jié)構(gòu)
第三章 ARM Cortex-M3 體系結(jié)構(gòu)
3.1 Cortex-M3 結(jié)構(gòu)框透視圖
3.2 CM3寄存器
3.3 堆棧模式切換
-
通過異常進(jìn)行堆棧切換
在線程模式主堆棧 產(chǎn)生異常–>進(jìn)入處理模式主堆棧-異常退出>進(jìn)入線程模式進(jìn)行堆棧。 -
通過MSR指令修改CONTROL[1]進(jìn)行堆棧切換 (一般不用)
CONTROL[1]=1;進(jìn)程堆棧
=0;//主堆棧
3.4 XPSR寄存器
? XPSR為程序狀態(tài)寄存器組。是32位的寄存器,有三個(gè)狀態(tài)。
為什么需要執(zhí)行狀態(tài)寄存器EPSR ?
LDM、 STM和If-then指令, 為多周期指令, 如果在執(zhí)行以上多周期指令時(shí)發(fā)生異常, 處
理器會(huì)暫時(shí)停止以上指令的操作, 進(jìn)入異常,
這時(shí)需要保護(hù)現(xiàn)場。
3.5 總線接口
有關(guān)DMA說明:借鑒(https://blog.csdn.net/as480133937/article/details/104927922?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165395856816780366585832%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=165395856816780366585832&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2alltop_positive~default-1-104927922-null-null.142v11pc_search_result_control_group,157v12control&utm_term=DMA&spm=1018.2226.3001.4187)
3.6 存儲(chǔ)器格式
? Cortex-M3 既可使用大端格式也可使用小端格式訪問存儲(chǔ)器。
通常是以小端格式訪問代碼, 小端格式是ARM 處理器的默認(rèn)存儲(chǔ)器格式。
-
小端存儲(chǔ)器系統(tǒng):
在小端格式中, 數(shù)據(jù)的高字節(jié)存放在高地址中。 -
大端存儲(chǔ)器系統(tǒng):
在大端格式中, 數(shù)據(jù)的高字節(jié)存放在低地址中。
3.7位帶操作
在Cortex M3 中,為了方便對位進(jìn)行操作,設(shè)有位帶區(qū)和位帶別名區(qū)。
映射公式::
bit_word_addr = bit_band_base + (byte_offset x 32) +bit_number × 4
//位帶別名區(qū)地址=位基地址+偏移地址*32+位數(shù)*4
/*例如:SRAM 位段區(qū)中地址為 0x20000300 的字節(jié)中的位 2 被映射到別名區(qū)中的地址為: 0x22006008( =0x22000000 + (0x300*32) + (2*4)) 的字。*/
3.8 異常與中斷
? 在 ARM 編程領(lǐng)域中,凡是打斷程序順序執(zhí)行的事件,都被稱為異常(exception),中斷是異常的一種程序代碼也可以主動(dòng)請求進(jìn)入異常狀態(tài)的(常用于系統(tǒng)調(diào)用)。也就是CPU需要立刻處理的內(nèi)部/外部事件。
? 所有的 Cortex-M處理器都會(huì)提供一個(gè)用于中斷處理的嵌套向量中斷控制器(NVIC)。除了中斷請求,還有其他需要服務(wù)的事件,將其稱為“異常”。
在中斷中,會(huì)有堆棧占用。 原因是保存返回地址和寄存器上下文。寄存器入棧又CPU硬件自動(dòng)完成。
中斷和輪詢:
- 中斷:(用專門的中斷服務(wù)程序來處理事件)
-適于處理對響應(yīng)要求非常高的事件
-適于處理持續(xù)事件非常短的事件
-適于低功耗的應(yīng)用
-程序設(shè)計(jì)較復(fù)雜 - 輪詢(會(huì)消耗大量的CPU處理時(shí)間,可能會(huì)丟失關(guān)鍵事件)
-適于處理對時(shí)間響應(yīng)要求低的場合
-程序設(shè)計(jì)簡單
中斷的允許與禁止
全局中斷控制 – enable/disable ALL interrupts
? -CPU的CCR寄存器中一個(gè)特殊位
? -在復(fù)位后,全局禁止位是置起的
? -中斷發(fā)生后,全局禁止位也被置起
? -通常在復(fù)位后所有的中斷都被禁止了
中斷向量表:
? - 中斷向量表是一段連續(xù)的存儲(chǔ)空間
? - 在復(fù)位后有默認(rèn)的起始位置
? - 每個(gè)中斷在向量表中都有相應(yīng)的表項(xiàng),該表項(xiàng)的值為該中斷對應(yīng)的服務(wù)程序的地址(地址指針)
? - 由程序代碼確定中斷向量表的每個(gè)表項(xiàng)
? - 中斷向量表的位置是可以通過改寫中斷向量基址寄存器重新定位的
中斷向量表的作用:
? 每一種中斷發(fā)生對應(yīng)要處理的函數(shù)入口地址填在這里。 CPU就知道對應(yīng)中斷發(fā)生的時(shí)候要做什么操作 。
? 根據(jù)這個(gè)表去查程序的入口地址就能知道應(yīng)該執(zhí)行什么樣的中斷子程序。
中斷、異常過程:
占先:
? 在異常處理程序中, 一個(gè)新的異常比當(dāng)前的異常優(yōu)先級更高, 處理器打斷當(dāng)前的流程, 響應(yīng)優(yōu)先級更高的異常, 此時(shí)產(chǎn)生中斷嵌套。
末尾連鎖:
? 一個(gè)中斷返回后, 系統(tǒng)立即處理掛起的中斷。能夠加快中斷響應(yīng)。
遲來:
? 遲來是處理器用來加速占先的一種機(jī)制。
? 前一個(gè)中斷尚未進(jìn)入執(zhí)行階段, 遲來中斷優(yōu)先級比前一個(gè)
中斷高, 則搶占前一個(gè)中斷得到優(yōu)先服務(wù)
第四章 STM32F103系列
- 最小系統(tǒng)原理圖
第五章 KEIL5的使用與STM32cubemx軟件
? 具體內(nèi)容,SCND搜索即可。
第六章GPIO原理及應(yīng)用
6.1 寄存器存儲(chǔ)映射
存儲(chǔ)器本身不具有地址信息,它的地址是由芯片廠商或用戶分配,給存儲(chǔ)器分配地址的過程就稱為存儲(chǔ)器映射。
片上外設(shè)區(qū)分為三條總線,根據(jù)外設(shè)速度的不同,不同總線掛載著不同的外設(shè), APB1掛載低速外設(shè), APB2 和 AHB 掛載高速外設(shè)。相應(yīng)總線的最低地址我們稱為該總線的基地 址,總線基地址也是掛載在該總線上的首個(gè)外設(shè)的地址。其中 APB1 總線的地址最低,片上外設(shè)從這里開始,也叫
6.2 外設(shè)寄存器
每個(gè)外設(shè)寄存器為32bit,占四個(gè)字節(jié)。
具體外設(shè)寄存器作用,見《1-STM32F10x-中文參考手冊.pdf》第八章GPIO寄存器的描述。
6.3 GPIO的輸入與輸出:
- 推挽輸出與開漏輸出:
-
推挽輸出
? 推挽輸出模式,是根據(jù)這兩個(gè) MOS 管的工作方式來命名的。在該結(jié)構(gòu)中輸入高電平時(shí),經(jīng)過反向后,上方的 P-MOS 導(dǎo)通,下方的 NMOS關(guān)閉,對外輸出高電平;而在該結(jié)構(gòu)中輸入低電平時(shí),經(jīng)過反向后,N-MOS 管導(dǎo)通, P-MOS 關(guān)閉,對外輸出低電平。 當(dāng)引腳高低電平切換時(shí),兩個(gè)管子輪流導(dǎo)通, P 管負(fù)責(zé)灌電流, N 管負(fù)責(zé)拉電流,使其負(fù)載能力和開關(guān)速度都比普通的方式有很大的提高。
? 使用場合:推挽輸出模式一般應(yīng)用在輸出電平為 0 和 3.3 伏而且需要高速切換開關(guān)狀態(tài)的場合。 在STM32的應(yīng)用中,除了必須用開漏模式的場合,我們都習(xí)慣使用推挽輸出模式 -
開漏輸出
? 在開漏輸出模式時(shí),上方的 P-MOS 管完全不工作。如果我們控制輸出為 0,低電平, 則 P-MOS管關(guān)閉, N-MOS管導(dǎo)通,使輸出接地,若控制輸出為 1 (它無法直接輸出高電平) 時(shí),則 P-MOS 管和 N-MOS 管都關(guān)閉,所以引腳既不輸出高電平,也不輸出低電平,為高阻態(tài)。
? 特點(diǎn):正常使用時(shí)必須外部接上拉電阻, 開漏輸出具有“線與”特性, 也就是說,若有很多個(gè)開漏模式引腳連接到一起時(shí),只有當(dāng)所有引腳都輸出高阻態(tài),才由上拉電阻提供高電平,此高電平的電壓為外部上拉電阻所接的電源的電壓。若其中一個(gè)引腳為低電平,那線路就相當(dāng)于短路接地,使得整條線路都為低電平, 0伏。
- GPIO結(jié)構(gòu)分析
6.4 外設(shè)寄存器使用方法:
/********ODR寄存器輸出高低電平********/
#define GPIO_ODR *(unsiged int*)(0x40010C0C)//
//GPIOB基地址 &GPIOB=0x40010C00;
//ODR偏移地址 &ODR=0x0C;
GPIO_ODR|= (1<<4);//第四個(gè)引腳輸出高電平
GPIO_ODR&= ~( 1<<2 );//第二個(gè)引腳輸出低電平
點(diǎn)亮LED的三個(gè)步驟:
- 開啟外設(shè)時(shí)鐘
- 配置GPIO模式
- 控制引腳電平
/************寄存器方式******/
// 開啟 GPIOC 端口 時(shí)鐘
*(unsigned int *)0X40021018 |= (1<<4);//RCC_APB2ENR寄存器
#define GPIOC_CRL *(unsiged int*)(0X40011000)//
// 清空控制 PC2 的端口位
2 *(unsigned int *)GPIOC_CRL &= ~( 0x0F<< (4*2));
3 // 配置 PC2 為通用推挽輸出,速度為 10M
4 *(unsigned int *)GPIOC_CRL |= ( 1<<(4*2) );
/*******GPIO標(biāo)準(zhǔn)庫函數(shù)初始化****/
void LED_GPIO_Config(void)
{
/*定義一個(gè)GPIO_InitTypeDef類型的結(jié)構(gòu)體*/
GPIO_InitTypeDef GPIO_InitTStruct;
/*開啟GPIO相關(guān)外設(shè)時(shí)鐘*/
RCC_APB2PeriphClockCmd(LED1_GPIO_CLK|LED2_GPIO_CLK, ENABLE);
/*定義GPIO結(jié)構(gòu)體成員*/
GPIO_InitTStruct.GPIO_Pin = LED1_GPIO_PIN;//初始化引腳
GPIO_InitTStruct.GPIO_Mode = GPIO_Mode_Out_PP;//輸出模式
/*typedef enum
{ GPIO_Mode_AIN = 0x0,//模擬輸入
GPIO_Mode_IN_FLOATING = 0x04,//浮空輸入
GPIO_Mode_IPD = 0x28,//帶下拉輸入
GPIO_Mode_IPU = 0x48, //帶上拉輸入
GPIO_Mode_Out_OD = 0x14,//開漏輸出
GPIO_Mode_Out_PP = 0x10,//推挽輸出
GPIO_Mode_AF_OD = 0x1C,//復(fù)用開漏輸出
GPIO_Mode_AF_PP = 0x18//復(fù)用推挽輸出
}GPIOMode_TypeDef;*/
GPIO_InitTStruct.GPIO_Speed = GPIO_Speed_10MHz;
/*typedef enum
{
GPIO_Speed_10MHz = 1,//10MHz速度
GPIO_Speed_2MHz,//20MHz速度
GPIO_Speed_50MHz,//50MHz速度
}GPIOSpeed_TypeDef;*/
/*初始化LED1*/
GPIO_Init(LED1_GPIO_PORT, &GPIO_InitTStruct);//初始化
GPIO_SetBits(LED1_GPIO_PORT, LED1_GPIO_PIN);//寫入
/***LED2相同****/
}
void delay(uint32_t count)
{
for(; count!=0; count--);
}
//GPIO_SetBits(LED1_GPIO_PORT, LED1_GPIO_PIN);//寫入引腳狀態(tài)
//GPIO_ResetBits(LED1_GPIO_PORT, LED1_GPIO_PIN);//清楚狀態(tài)
第七章RCC時(shí)鐘配置
7.1時(shí)鐘特點(diǎn)
- 時(shí)鐘是指令執(zhí)行的基本時(shí)間間隔,時(shí)鐘頻率高,意味著CPU執(zhí)行運(yùn)算的能力強(qiáng)看門]狗/定時(shí)器/異步通信等都依賴穩(wěn)定的時(shí)鐘
- MCU內(nèi)部是一個(gè)統(tǒng)一的時(shí)鐘樹,外設(shè)的時(shí)鐘是從系統(tǒng)時(shí)鐘分頻得到的。
- 時(shí)鐘通常由外部晶體或振蕩器提供,使用外部的配置引|腳在復(fù)位時(shí)選擇時(shí)鐘輸入源。
- 廣泛應(yīng)用鎖相環(huán)技術(shù),將外部較低頻率的時(shí)鐘提高成內(nèi)部較高頻率的時(shí)鐘(better EMC&EMI)、
STM32一共有5個(gè)時(shí)鐘源HSI, HSE, LSI, LSE,PLL。
7.2 時(shí)鐘配置:
編程要點(diǎn)對應(yīng)著時(shí)鐘樹圖中的序號。
? 1、開啟 HSE/HSI
? 2、設(shè)置PLLXTPRE(HSE或HSE/2)
? 3、 打開PLL, 設(shè)置 PLL的時(shí)鐘來源,和 PLL的倍頻因子
? 4、 選擇 PLLCK為系統(tǒng)時(shí)鐘 SYSCLK
? 5、選擇要配置的總線時(shí)鐘
? 6、設(shè)置 AHB、 APB2、 APB1的預(yù)分頻因子
7.3 時(shí)鐘初始化
void SystemClock_Config(void)/******時(shí)鐘初始化 ********/
{
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;
/**Initializes the CPU, AHB and APB busses clocks */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
/**Initializes the CPU, AHB and APB busses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
/**Configure the Systick interrupt time
*/
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
/**Configure the Systick
*/
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
/* SysTick_IRQn interrupt configuration */
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}
第八章STM32中斷應(yīng)用
8.1 異常類型
? F103 在內(nèi)核水平上搭載了一個(gè)異常響應(yīng)系統(tǒng), 支持為數(shù)眾多的系統(tǒng)異常和外部中斷。其中系統(tǒng)異常有 8 個(gè)(如果把 Reset 和 HardFault 也算上的話就是 10 個(gè)),外部中斷有 60個(gè)。除了個(gè)別異常的優(yōu)先級被定死外,其它異常的優(yōu)先級都是可編程的。
8.2 NVIC介紹
? NVIC 是嵌套向量中斷控制器, 控制著整個(gè)芯片中斷相關(guān)的功能,它跟內(nèi)核緊密耦合,是內(nèi)核里面的一個(gè)外設(shè).
- NVIC特點(diǎn):
- 68個(gè)可屏蔽中斷通道(不包含16個(gè)Cortex?-M3的中斷線);
- 16個(gè)可編程的優(yōu)先等級(使用了4位中斷優(yōu)先級);
- 低延遲的異常和中斷處理;
- 電源管理控制;
- 系統(tǒng)控制寄存器的實(shí)現(xiàn);
- 嵌套向量中斷控制器(NVIC)和處理器核的接口緊密相連,可以實(shí)現(xiàn)低延遲的中斷處理和高效地 處理晚到的中斷。
-
NVIC寄存器設(shè)置
typedef struct { 2 __IO uint32_t ISER[8]; // 中斷使能寄存器 3 uint32_t RESERVED0[24]; 4 __IO uint32_t ICER[8]; // 中斷清除寄存器 5 uint32_t RSERVED1[24]; 6 __IO uint32_t ISPR[8]; // 中斷使能懸起寄存器 7 uint32_t RESERVED2[24]; 8 __IO uint32_t ICPR[8]; // 中斷清除懸起寄存器 9 uint32_t RESERVED3[24]; 10 __IO uint32_t IABR[8]; // 中斷有效位寄存器 11 uint32_t RESERVED4[56]; 12 __IO uint8_t IP[240]; // 中斷優(yōu)先級寄存器(8Bit wide) 13 uint32_t RESERVED5[644]; 14 __O uint32_t STIR; // 軟件觸發(fā)中斷寄存器 15 } NVIC_Type; /* 2 * 配置中斷優(yōu)先級分組:搶占優(yōu)先級和子優(yōu)先級 3 * 形參如下: 4 * @arg NVIC_PriorityGroup_0: 0 bit for 搶占優(yōu)先級 5 * 4 bits for 子優(yōu)先級 6 * @arg NVIC_PriorityGroup_1: 1 bit for 搶占優(yōu)先級 7 * 3 bits for 子優(yōu)先級 8 * @arg NVIC_PriorityGroup_2: 2 bit for 搶占優(yōu)先級 9 * 2 bits for 子優(yōu)先級 10 * @arg NVIC_PriorityGroup_3: 3 bit for 搶占優(yōu)先級 11 * 1 bits for 子優(yōu)先級 12 * @arg NVIC_PriorityGroup_4: 4 bit for 搶占優(yōu)先級 13 * 0 bits for 子優(yōu)先級 14 * @注意 如果優(yōu)先級分組為 0,則搶占優(yōu)先級就不存在,優(yōu)先級就全部由子優(yōu)先級控制 15 */void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup) 17 { 18 // 設(shè)置優(yōu)先級分組 19 SCB->AIRCR = AIRCR_VECTKEY_MASK | NVIC_PriorityGroup; 20 }
-
中斷編程特點(diǎn)
- 使能外設(shè)某個(gè)中斷,這個(gè)具體由每個(gè)外設(shè)的相關(guān)中斷使能位控制。
- 設(shè)置中斷優(yōu)先級分組
- 始化 NVIC_InitTypeDef 結(jié)構(gòu)體,配置中斷優(yōu)先級分組,設(shè)置搶占優(yōu)先級和子優(yōu)先級,使能中斷請求
- 寫中斷服務(wù)函數(shù)
-
程序編寫
//NVIC 初始化結(jié)構(gòu)體 1 typedef struct { 2 uint8_t NVIC_IRQChannel; // 中斷源 3 uint8_t NVIC_IRQChannelPreemptionPriority; // 搶占優(yōu)先級 4 uint8_t NVIC_IRQChannelSubPriority; // 子優(yōu)先級 5 FunctionalState NVIC_IRQChannelCmd; // 中斷使能或者失能 6 } NVIC_InitTypeDef; static void NVIC_Configuration(void) { NVIC_InitTypeDef NVIC_InitStructure; /* 配置NVIC優(yōu)先級組為1 */ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); /* 配置中斷源:按鍵1 */ NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn; /*配置搶占優(yōu)先級 */ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; /* 配置子優(yōu)先級 */ NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; /* 勢能中斷通道*/ NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); }
第九章EXTI外部中斷/事件控制器
9.1EXTI簡介
? EXTI(External interrupt/eventcontroller) —外部中斷/事件控制器,管理了控制器的 20 個(gè)中斷/事件線。每個(gè)中斷/事件線都對應(yīng)有一個(gè)邊沿檢測器,可以實(shí)現(xiàn)輸入信號的上升沿 檢測和下降沿的檢測。 EXTI 可以實(shí)現(xiàn)對每個(gè)中斷/事件線進(jìn)行單獨(dú)配置,可以單獨(dú)配置為中斷或者事件,以及觸發(fā)事件的屬性。
9.2 中斷事件線
? EXTI 有 20 個(gè)中斷/事件線,每個(gè) GPIO 都可以被設(shè)置為輸入線,占用 EXTI0 至 EXTI15,還有另外幾根用于特定的外設(shè)事件 。EXTI(0-15)---->引腳A-I(pin0-pin15)
9.3 EXTI程序?qū)崿F(xiàn)
- 編程要點(diǎn)
- 初始化用來產(chǎn)生中斷的 GPIO;
- 初始化 EXTI;
- 配置 NVIC;
- 編寫中斷服務(wù)函數(shù)
-
程序?qū)崿F(xiàn)
/*EXTI 初始化結(jié)構(gòu)體 1 typedef struct { 2. uint32_t EXTI_Line; // 中斷/事件線 3. EXTIMode_TypeDef EXTI_Mode; // EXTI 模式 4. EXTITrigger_TypeDef EXTI_Trigger; // 觸發(fā)類型 5 FunctionalState EXTI_LineCmd; // EXTI 使能 6 } EXTI_InitTypeDef;*/ /*****采用HAL庫編輯**/ void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOF_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOG_CLK_ENABLE(); /*Configure GPIO pins : PFPin PFPin PFPin PFPin */ GPIO_InitStruct.Pin = LED1_Pin|LED2_Pin|LED3_Pin|LED4_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOF, &GPIO_InitStruct); /*Configure GPIO pins : PGPin PGPin PGPin PGPin PGPin */ GPIO_InitStruct.Pin = JOY_SEL_Pin|JOY_DOWN_Pin|JOY_RIGHT_Pin|JOY_LEFT_Pin |JOY_UP_Pin; GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;//上升沿出發(fā)// GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(GPIOG, &GPIO_InitStruct); /* EXTI interrupt init*/ HAL_NVIC_SetPriority(EXTI9_5_IRQn, 0, 0)//中斷線 搶占優(yōu)先級 子優(yōu)先級 HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);//使能 HAL_NVIC_SetPriority(EXTI15_10_IRQn, 0, 0); HAL_NVIC_EnableIRQ(EXTI15_10_IRQn); } /********在stm32f1xx_it.c中***/ void EXTI9_5_IRQHandler(void) { /* USER CODE BEGIN EXTI9_5_IRQn 0 */ /* USER CODE END EXTI9_5_IRQn 0 */ HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_7);//處理引腳7中斷線 HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_8); /* USER CODE BEGIN EXTI9_5_IRQn 1 */ /* USER CODE END EXTI9_5_IRQn 1 */ } void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)/****HAL庫自帶*/ { /* EXTI line interrupt detected */ if (__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != RESET)//__HAL_GPIO_EXTI_GET_IT判斷事是否產(chǎn)生中斷標(biāo)志位,返回SET和RESET,具體見EXTI_PR寄存器 { __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin); HAL_GPIO_EXTI_Callback(GPIO_Pin);//修改回調(diào)函數(shù) } } HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { //中斷編寫內(nèi)容 }
第十章 定時(shí)器
10.1 SYSTICK—系統(tǒng)定時(shí)器
-
定義:SysTick—系統(tǒng)定時(shí)器是屬于 CM3 內(nèi)核中的一個(gè)外設(shè),內(nèi)嵌在 NVIC 中。系統(tǒng)定時(shí)器 是一個(gè) 24bit 的向下遞減的計(jì)數(shù)器,計(jì)數(shù)器每計(jì)數(shù)一次的時(shí)間為 1/SYSCLK,一般我們設(shè)置 系統(tǒng)時(shí)鐘 SYSCLK等于 72M。當(dāng)重裝載數(shù)值寄存器的值遞減到 0的時(shí)候,系統(tǒng)定時(shí)器就產(chǎn)生一次中斷,以此循環(huán)往復(fù)。因?yàn)?SysTick 是屬于 CM3 內(nèi)核的外設(shè),所以所有基于CM3 內(nèi)核的單片機(jī)都具有這個(gè) 系統(tǒng)定時(shí)器,使得軟件 CM3單片機(jī)中可以很容易的移植。系統(tǒng)定時(shí)器一般用于操作系統(tǒng), 用于產(chǎn)生時(shí)基,維持操作系統(tǒng)的心跳。
-
四個(gè)寄存器
-
計(jì)算與程序?qū)崿F(xiàn)
/*******計(jì)算公式 T=reload*(1/clk);//clk 為8MHz 或者72MHz //例如reload=72000,為1ms
/*通過查詢CTRL的特定位數(shù)*/ void SysTick_Delay_ms(uint32_t ms) { uint32_t i; SysTick_Config(72000);//1ms for(i=0; i<ms; i++) { //查詢Systick的cTRL寄存器 //查看第16位是否為1,若不是則表面reload沒有減到零,若是則跳出while,進(jìn)入下一個(gè)for while( !((SysTick->CTRL) & (1<<16)) ); } /*做足夠個(gè)循環(huán)后失能systick*/ SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; } volatile uint32_t isr_ms; /*通過中斷服務(wù)函數(shù)實(shí)現(xiàn)要求*/ void SysTick_Delay_ms_INT(uint32_t ms) { isr_ms = ms; SysTick_Config(72000); while(isr_ms); /* 失能 */ SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; }
10.2 TIM定時(shí)器
-
定時(shí)器分類
-
基本定時(shí)器
-
功能介紹:
1-計(jì)數(shù)器16bit, 只能向上計(jì)數(shù),只有TIM6和TIM7
2-沒有外部的GPIO,是內(nèi)部資源, 只能用來定時(shí)
3-時(shí)鐘來自PCLK1,為72M,可實(shí)現(xiàn)1~65536分頻 -
基本定時(shí)器功能框圖
-
定時(shí)時(shí)間的計(jì)算
1、 PSC = 72-1,定時(shí)器頻率=72M/(PSC+1)=1MHZ
2、 ARR = 1000-1,從0計(jì)數(shù)到999,則計(jì)了1000次
3、中斷周期T = 1000 *1/1000000 = 1mS -
程序?qū)崿F(xiàn)定時(shí)
typedef struct { uint16_t TIM_Prescaler;//分頻因子 uint16_t TIM_CounterMode;//計(jì)數(shù)模式,基本定時(shí)器只能向上計(jì)數(shù) uint32_t TIM_Period;//自動(dòng)重裝載值 uint16_t TIM_ClockDivision;//外部輸入時(shí)鐘分頻因子,基本定時(shí)器沒有 uint8_t TIM_RepetitionCounter;//重復(fù)計(jì)時(shí)器,基本定時(shí)器沒有,高級定時(shí)器專用 }TIM_TimeBaseInitTypeDef;
-
高級定時(shí)器
-
高級定時(shí)器功能
1-計(jì)數(shù)器16bit,上/下/兩邊 計(jì)數(shù), TIM1和TIM8,還
有一個(gè)重復(fù)計(jì)數(shù)器RCR,獨(dú)有。
2-有4個(gè)GPIO,其中通道1~3還有互補(bǔ)輸出GPIO
3-時(shí)鐘來自PCLK2,為72M,可實(shí)現(xiàn)1~65536分頻 -
引腳分布:
-
高級定時(shí)器功能框圖
-
框圖講解:
? a. 時(shí)鐘源:
? 1-內(nèi)部時(shí)鐘源CK_INT
? 2-外部時(shí)鐘模式1—外部的GPIO Tix(x=1 2 3 4)
? 3-外部時(shí)鐘模式2—外部的GPIO ETR
? 4-內(nèi)部觸發(fā)輸入? b. 內(nèi)部時(shí)鐘源
? 1-內(nèi)部時(shí)鐘源來自RCC的TIMx_CLK? c. 外部時(shí)鐘1
? d. 外部時(shí)鐘2
-
-
控制器
1-控制器就是用來控制的,發(fā)送命令的
2-CR1、 CR2、 SMCR、 CCER,主要學(xué)習(xí)這幾個(gè)寄存
器即可。 -
時(shí)基單元
- 時(shí)基單元組成 1-16位的預(yù)分頻器 PSC, PSC 2-16位的計(jì)數(shù)器CNT, CNT 3-8位的重復(fù)計(jì)數(shù)器RCR, RCR(高級定時(shí)器獨(dú)有) 4-16位的自動(dòng)重裝載寄存器ARR, ARR
-
預(yù)分頻器
- 預(yù)分頻器PSC
預(yù)分頻器PSC,有一個(gè)輸入時(shí)鐘CK_ PSC和一個(gè)輸出時(shí)鐘CK_ CNT。輸入時(shí)鐘
CK_ PSC就是上面時(shí)鐘源的輸出,輸出CK_ CNT則用來驅(qū)動(dòng)計(jì)數(shù)器CNT計(jì)數(shù)。通過設(shè)置
預(yù)分頻器PSC的值可以得到不同的CK CNT,實(shí)際計(jì)算為: fok _CN等于
fck psc(PSC[15:0]+1),可以實(shí)現(xiàn)1至65536分頻。
- 預(yù)分頻器PSC
-
計(jì)數(shù)器(上/下/兩邊)
- (1) 遞增計(jì)數(shù)模式下,計(jì)數(shù)器從0開始計(jì)數(shù),每來一個(gè)CK_ CNT脈沖計(jì)數(shù)器就增加1,直到計(jì)數(shù)器的值與自動(dòng)重載寄存器ARR值相等,然后計(jì)數(shù)器又從0開始計(jì)數(shù)并生成計(jì)數(shù)器上溢事件,計(jì)數(shù)器總是如此循環(huán)計(jì)數(shù)。如果禁用重復(fù)計(jì)數(shù)器,在計(jì)數(shù)器生成上溢事
件就馬上生成更新事件(UEV); - 遞減計(jì)數(shù)模式下, 計(jì)數(shù)器從自動(dòng)重載寄存器ARR值開始計(jì)數(shù),每來-一個(gè)CK CNT脈沖計(jì)數(shù)器就減1,直到計(jì)數(shù)器值為0,然后計(jì)數(shù)器又從自動(dòng)重載寄存器ARR值開始遞減計(jì)數(shù)并生成計(jì)數(shù)器下溢事件,計(jì)數(shù)器總是如此循環(huán)計(jì)數(shù)。如果禁用重復(fù)計(jì)數(shù)器,在計(jì)數(shù)器生成下溢事件就馬上生成更新事件;如果使能重復(fù)計(jì)數(shù)器,每生成- -次下溢事件重復(fù)計(jì)數(shù)器內(nèi)容就減1,直到重復(fù)計(jì)數(shù)器內(nèi)容為0時(shí)才會(huì)生成更新事件.
- 中心對齊模式下,計(jì)數(shù)器從0開始遞增計(jì)數(shù),直到計(jì)數(shù)值等于(ARR-1)值生成計(jì)數(shù)器上溢事件,然后從ARR值開始遞減計(jì)數(shù)直到1生成計(jì)數(shù)器下溢事件。然后又從0開始計(jì)數(shù),如此循環(huán)。每次發(fā)生計(jì)數(shù)器上溢和下溢事件都會(huì)生成更新事件。
- (1) 遞增計(jì)數(shù)模式下,計(jì)數(shù)器從0開始計(jì)數(shù),每來一個(gè)CK_ CNT脈沖計(jì)數(shù)器就增加1,直到計(jì)數(shù)器的值與自動(dòng)重載寄存器ARR值相等,然后計(jì)數(shù)器又從0開始計(jì)數(shù)并生成計(jì)數(shù)器上溢事件,計(jì)數(shù)器總是如此循環(huán)計(jì)數(shù)。如果禁用重復(fù)計(jì)數(shù)器,在計(jì)數(shù)器生成上溢事
-
自動(dòng)重裝載寄存器
? 自動(dòng)重載寄存器ARR自動(dòng)重載寄存器ARR用來存放與計(jì)數(shù)器CNT比較的值,如果兩個(gè)值相等就遞減重復(fù)計(jì)數(shù)器??梢酝ㄟ^TIMx_ CRI寄存器的ARPE位控制自動(dòng)重載影子寄存器功能,如果ARPE位置1,自動(dòng)重載影子寄存器有效,只有在事件更新時(shí)才把TIMx_ ARR值賦給影子寄存器。如果ARPE位為0,則修改TIMx ARR值馬上有效。
-
輸入捕獲的作用和原理
? 輸入捕獲可以對輸入的信號的上升沿,下降沿或者 雙邊沿進(jìn)行捕獲,常用的有測量輸入信號的脈寬和測量PWM輸入信號的頻率和占空比這兩種。輸入捕獲的大概的原理就是,當(dāng)捕獲到信號的跳變沿的時(shí)候,把數(shù)器CNT的值鎖存到捕獲寄存器CCR中,把前后兩次捕獲到的CCR寄存器中的值相減,就可以算出脈寬或者頻率。如果捕獲的脈寬的時(shí)間長度超你的捕獲定時(shí)器的周期,就會(huì)發(fā)生溢出,這個(gè)我們需要做額外的處理。- 輸入通道
當(dāng)使用需要被測量的信號從定時(shí)器的外部引腳TIMx_CH1/2/3/4 迚入,通常叫 TI1/2/3/4,在后面的捕獲講解中對于要被測量的信號我們都以 TIx 為標(biāo)準(zhǔn)叫法。 - 輸入濾波和邊沿檢測
- 捕獲通道
- 預(yù)分頻器
- 捕獲寄存器
- 輸入通道
-
輸出比較
-
輸出比較的作用
? 輸出比較就是通過定時(shí)器的外部引腳對外輸出控制信號,有凍結(jié)、將通道X(x=1,2,3,4)設(shè)置為匹配時(shí)輸出有效電平、將通道X設(shè)置為匹配時(shí)輸出無效電平、翻轉(zhuǎn)、強(qiáng)制變?yōu)闊o效電平、強(qiáng)制變?yōu)橛行щ娖健WM1和PWM2這八種模式,具體使用哪種模式由寄存器CCMRx的位0CxM[2:0]配置。其中PWM模式是輸出比較中的特例,使用的也最多。文章來源:http://www.zghlxwxcb.cn/news/detail-471411.html
-
文章來源地址http://www.zghlxwxcb.cn/news/detail-471411.html
/*******定義定時(shí)器***********/
void MX_TIM2_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig;
TIM_MasterConfigTypeDef sMasterConfig;
TIM_OC_InitTypeDef sConfigOC;
htim2.Instance = TIM2;
htim2.Init.Prescaler = 0;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 0;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
if (HAL_TIM_PWM_Init(&htim2) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 32;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
sConfigOC.Pulse = 64;
if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
sConfigOC.Pulse = 0;
if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
sConfigOC.Pulse = 32;
if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_4) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
HAL_TIM_MspPostInit(&htim2);
}
/*******基本定時(shí)器*************/
static void BASIC_TIM_Mode_Config(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
//開啟定時(shí)器時(shí)鐘,即內(nèi)部時(shí)鐘CK_INT=72M
BASIC_TIM_APBxClock_FUN(BASIC_TIM_CLK, ENABLE);
//自動(dòng)重裝載寄存器的值,累計(jì)TIM_Peiod+1個(gè)頻率后產(chǎn)生一個(gè)更新或者中
TIM_TimeBaseStructure.TIM_Period = BASIC_TIM_Period;
/時(shí)鐘分頻因子,基本定時(shí)器沒有,不用管
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
// 計(jì)數(shù)器計(jì)數(shù)模式,基本定時(shí)器只能向上計(jì)數(shù),沒有計(jì)數(shù)模式的設(shè)置
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
// 重復(fù)計(jì)數(shù)器的值,基本定時(shí)器沒有,不用管
TIM_TimeBaseStructure.TIM_RepetitionCounter=0;
// 初始化定時(shí)器
TIM_TimeBaseInit(BASIC_TIM, &TIM_TimeBaseStructure);
// 清楚計(jì)數(shù)器中斷標(biāo)志位
TIM_ClearFlag(BASIC_TIM, TIM_FLAG_Update);
TIM_ITConfig(BASIC_TIM,TIM_IT_Update,ENABLE);// 開啟計(jì)數(shù)器中斷
TIM_Cmd(BASIC_TIM, ENABLE); // 使能計(jì)數(shù)器
}
到了這里,關(guān)于嵌入式學(xué)習(xí)stm32基礎(chǔ)知識(期末復(fù)習(xí))的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!