1.基礎知識

阿Q熊發表於2024-07-15

微控制器:Single-Chip Microcomputer,單片微型計算機,是一種積體電路晶片

CPU:CPU
記憶體:SRAM
硬碟:FLASH
主機板:外設

儀器儀表:電源/示波器/焊臺
家用電器:空調/冰箱/洗衣機
工業控制:機器人/PLC/電梯
汽車電子:GPS/ABS/胎壓監測

1.基礎知識:資料與程式儲存在同一儲存器,分時複用

1.基礎知識

CoreMark分數:https://www.eembc.org/coremark/scores.php
ARM公司官網:https://www.arm.com/
ARM開發者官網:https://developer.arm.com/

STM32:
ST:意法半導體 M:MCU/MPU 32:32位
ST累計推出了:5大類、18個系列、1000多個型號的Cortex核心微控制器
ST中文社群網:https://www.stmcu.org.cn
ST官網: https://www.st.com
正點原子論壇:www.openedv.com/forum.php
STM32 主要分兩大塊, MCU 和 MPU, MCU 不能跑 Linux,而 MPU可以跑 Linux。

晶片的基本引數:
1,主頻/FLASH/SRAM
2,工作電壓/最大電流
3,IO引腳接入電壓範圍
4,單個IO引腳最大電流

最小系統:電源、復位、啟動、晶振、除錯
電源:
VDD/VSS
VDDA/VSSA:模擬部分供電
VREF+/VREF- :給內部 ADC/DAC 提供參考電壓
VBAT:給RTC和後備區域供電。
復位:
NRST:低電平復位
啟動:
BOOT0/BOOT1:啟動選擇引腳,一般接下拉電阻
晶振:
OSC_IN /OSC_OUT:外部 HSE 晶振,提供高精度系統時鐘
OSC32_IN /OSC32_OUT:外部 LSE 晶振,給內部 RTC 提供時鐘
除錯:
SWCLK/SWDIO
IO分配:
IIC:
IIC_SCL、IIC_SDA
SPI :
SPI_CS、MOSI、MISO、SCK
TIM:
TIM_CH1/2/3/4、ETR/1N/2N/3N、BKIN 等
USART、UART:
USART 有 USART_TX/RX/CTS/RTS/CK 訊號
UART 有 UART_TX/RX 兩個訊號
U(S)ART_TX、U(S)ART_RX
USB :
USB_DP 和 USB_DM
CAN:
CAN_RX 和 CAN_TX。
ADC :
ADC_IN0 ~ ADC_IN15
DAC :
DAC_OUT1 、DAC_OUT2
SDIO :
SDIO_D0/1/2/3、SCK、CMD
FSMC:
FSMC_D0~15/A0~25/ NBL0~1/NE1~4/NCE2~3/NOE/NWE/NWAIT/CLK 等
整合開發環境(IDE)
MDK--Keil
EWARM--IAR
模擬器:
DAP--ARM:免驅動
STLINK--ST
JLINK--Segger
串列埠除錯助手:
XCOM--正點原子
SSCOM--丁丁

獲取MDK:
MDK安裝 = MDK軟體安裝 + 器件支援包
MDK軟體下載:https://www.keil.com/download/product
器件支援包下載:https://www.keil.com/dd2/pack/
複製下載演算法到Flash資料夾,如 D:\MDK5.34\ARM\Flash(可選)
安裝CH340 USB虛擬串列埠驅動,資料線插入開發板中

程式在Projects\MDK-ARM中

I/O :表示輸入/輸出引腳

編譯結果看:Build Output視窗
資料型別:佔用Flash or SRAM:說明
Code:表示程式碼大小
RO-Data:表示只讀資料所佔的空間大小,一般是指 const 修飾的資料大小。
RW-Data:初值為非 0的可讀可寫資料
ZI-Data:初值為0 的可讀可寫資料
FLASH佔用:Code+RO+RW
SRAM佔用:RW+ZI

hex檔案在Output中

STM32 常見的下載方式有三種:
串列埠下載: BOOT0 接 3.3V、 BOOT1 接 GND、按復位
SWD 下載:直接下載,特殊情況需 BOOT0接 3.3V,按復位
JTAG 下載:直接下載,特殊情況需 BOOT0接 3.3V,按復位

利用串列埠給 STM32 下載程式碼:
USB_UART 透過 USB 線連線電腦->電源燈亮起(藍色)->USART1的 RXD、PA9,TXD 、PA10透過跳線帽連線->BOOT0、GND,BOOT1、GND透過跳線帽連線->按一下復位按鍵->使用上位機軟體下載程式碼->雙擊開啟 ATK-XISP->波特率推薦設定為 76800->選擇 DTR 的低電平復位,RTS 高電平進 BootLoader->下載成功後,會有“共寫入 xxxxKB,進度 100%,耗時 xxxx 毫秒”

使用 DAP 下載與除錯程式:

DAP 透過 USB 線連線電腦,透過 20P 灰排線連線開發板->開發板供電->
開啟MDK IDE:
魔術棒->Debug->use: CMSIS-DAP Debugger->勾選Run to main->
點選 Settings->Port:SW->Max Clock:8Mhz->
Utilities ->勾選 Use Debug Driver->點選 Settings->選中 Reset and Run->如果沒有 flash 演算法,點選 Add 按鈕自行新增->
F7 ->F8

使用 DAP 模擬除錯程式:
Register:暫存器視窗
Disassembly:反彙編視窗,方便從彙編級別檢視程式執行狀態
Call Stack + Locals:呼叫關係和區域性變數視窗,檢視函式呼叫關係,以及函式的區域性變數

1.基礎知識
Debug 工具條

關閉Disassembly視窗->新增Watch1視窗->雙擊 Enter expression,將全域性變數: g_fac_us (在 delay.c 裡面定義)加入 Watch1 視窗->
在 delay_init 函式處放置一個斷點->點選執行到該斷點處->執行進去->執行過去(g_fac_us值顯示出來)->執行進去
從 Call Stack + Locals 視窗看到函式的呼叫關係,其原則是: 從下往上看,即下一個函式呼叫了上一個函式

MDK5 使用技巧:
自定義字型顏色:
設定->Encoding:Chinese GB2312(Simplified)->勾選View White Space(編輯器的空格可見)->勾選Insert spaces for tabs(程式碼對齊)->Tab size:4->
Colors & Fonts 選項卡->C/C++ Editor Files(設定自己的程式碼的字型和顏色)->
User Keywords 選項卡,設定使用者定義關鍵字

看看某個變數或陣列是在哪個地方定義,快速定位:
魔術棒->Output->勾選 Browse Information->編譯->
右鍵->Go to Definition Of

快速註釋/消註釋塊程式碼的功能->右鍵->高階(Advanced)->註釋選擇(Comment Selection)

快速開啟標頭檔案:右鍵->Open Document

C 語言基礎知識:
位操作:
按位與:&
按位或:|
按位異或:^
按位取反:~
左移:<<
右移:>>
微控制器開發中的一些實用技巧。
1,在不改變其他位的值的狀況下,對某幾個位進行設值。用&運算子進行清零操作, 然後用|運算子設值,
比如:要改變 GPIOA 的 CRL 暫存器 bit6(第 6 位)的值為 1
GPIOA->CRL &= 0XFFFFFFBF; / 將第 bit6 清 0 /
然後再與需要設定的值進行|或運算
GPIOA->CRL |= 0X00000040; / 設定 bit6 的值為 1,不改變其他位的值 /
2.移位操作提高程式碼的可讀性
比如:將 CTRL 暫存器的第 1 位(從 0 開始算起)設定為 1
SysTick->CTRL |= 1 << 1;
3.~按位取反操用於清除某一個/某幾個位
比如:設定 CTRL 暫存器的第 0 位(最低位)為 0,其他位的值保持不變。
SysTick->CTRL &= ~(1 << 0) ; / 關閉 SYSTICK /
4.^按位異或操,用於控制某個位翻轉
比如:使 PB5 的輸出狀態翻轉一次
GPIOB->ODR ^= 1 << 5;

define :預處理命令,它用於宏定義
常見的格式:define 識別符號 字串
識別符號:宏名。

ifdef 條件編譯:條件編譯命令最常見的形式為:
#ifdef 識別符號
  程式段 1
#else
  程式段 2
#endif
當識別符號已經被定義過(一般是用#define 命令定義),則對程式段 1 進行編譯, 否則編譯程式段 2。 其中#else 部分也可以沒有

extern 外部申明:
extern :置於變數或者函式前,以表示變數或者函式的定義在別的檔案中。 extern 申明變數可以多次,但定義只有一次

typedef:為現有型別建立一個新的名字,或稱為型別別名,用來簡化變數的定義。定義結構體的型別別名和列舉型別。
typedef struct
{
  __IO uint32_t CRL;
  __IO uint32_t CRH;
  …
} GPIO_TypeDef;

宣告結構體型別:
struct 結構體名
{
  成員列表;
}變數名列表;
在結構體申明的時候可以定義變數,也可以申明之後定義:struct 結構體名字 結構體變數列表 ;
結構體成員變數的引用方法是:結構體變數名字.成員名

指標:本質是指向一個地址,從而可以訪問一片記憶體區域。
申明指標我們一般以 p 開頭:char * p_str = “This is a test!”;
p_num:變數的地址
*p_num:指向的地址所儲存的值
&p_num:指標自身的地址

暫存器:微控制器內部一種特殊的記憶體,它可以實現對微控制器各個功能的控制
STM32 暫存器分為兩類:核心暫存器和外設暫存器
核心暫存器:
1.核心相關暫存器:包含 R0~R15、 xPSR、特殊功能暫存器等
2.中斷控制暫存器:包含 NVIC 和 SCB 相關暫存器,
NVIC: ISER、 ICER、ISPR、 IP 等;
SCB: VTOR、 AIRCR、 SCR 等
3.SysTick 暫存器:CTRL、 LOAD、 VAL、CALIB
4.記憶體保護暫存器:可選功能, STM32F407 沒有
5.除錯系統暫存器:ETM、 ITM、 DWT、IPIU 等相關暫存器
重點關心中斷控制暫存器和 SysTick 暫存器
外設暫存器:
包含 GPIO、 UART、 IIC、 SPI、 TIM、 DMA、 ADC、 DAC、RTC、 I/WWDG、 PWR、 CAN、 USB 等各種外設暫存器

儲存器本身是沒有地址資訊的,儲存器分配地址的過程就叫儲存器對映。
給暫存器的地址命名的過程就叫暫存器對映。
暫存器的地址=外設基地址+地址偏移量
=匯流排基地址(BUS_BASE_ADDR)+匯流排基地址的偏移量(PERIPH_OFFSET)+外設基地址的偏移量(REG_OFFSET)
例如:GPIOB_ODR地址 = AHB1匯流排基地址 + GPIOB外設偏移量 + 暫存器偏移量
外設基地址在stm32參考手冊2.3儲存器對映中檢視

/*GPIOB_ODR 暫存器的地址為: 0x4002 0414, 假設我們要控制GPIOB 的 16 個 IO 口都輸出 1*/
#define GPIOB_ODR      *(unsigned int *)(0x40020414)
GPIOB_ODR = 0XFFFF;
/*這個宏定義過程就可以稱之為暫存器的對映。*/
STM32F407所有暫存器對映都在stm32f407xx.h裡面完成
stm32f407xx.h檔案主要包含五個部分內容
1.中斷編號定義:定義 IRQn_Type 列舉型別,包含STM32內部所有中斷編號(中斷號),方便後續編寫程式碼
2.外設暫存器結構體型別定義:以外設為基本單位,使用結構體型別定義對每個外設的所有暫存器進行封裝,方便後面的暫存器對映
3.暫存器對映:定義匯流排地址和外設基地址;使用外設結構體型別定義將外設基地址強制轉換成結構體指標,完成暫存器對映
4.暫存器位定義:定義外設暫存器每個功能位的位置及掩碼
5.外設判定:判斷某個外設是否合法(即是否存在該外設)
暫存器對映主要有兩個組成部分:外設暫存器結構體型別定義、暫存器對映
包括3個步驟:
1, 外設暫存器結構體型別定義
2, 外設基地址定義
3, 暫存器對映(透過將外設基地址強制轉換為外設結構體型別指標即可)
暫存器對映原理:
1,結構體地址自增;
2,地址強制轉換;
環境搭建:
新建5個資料夾:
Drivers:與硬體相關的驅動層檔案
BSP:開發闆闆級支援包驅動程式碼,如LED、蜂鳴器、按鍵各種外設驅動
CMSIS: CMSIS 底層程式碼
Device
Include
STM32F4xx_HAL_Driver
Inc
Src
SYSTEM:系統級核心驅動程式碼,如 sys.c、 delay.c 和 usart.c 等,複製system檔案
  STM32F4xx_HAL_Driver:存放hal庫檔案
Middlewares:中間層元件檔案、第三方中間層檔案,如: USMART、MALLOC、 TEXT、 FATFS、 USB、 LWIP、各種 OS、各種 GUI 等等。
Output:工程編譯輸出檔案
Projects:MDK 工程檔案
  MDK-ARM
User:main.c、stm32f4xx_hal_conf.h、stm32f4xx_it.c、stm32f4xx_it.h

新建一個工程框架:
開啟 MDK 軟體->專案->新的->STM32 型號(要安裝對應的器件 pack 才會顯示這些內容)->
自動建立了 3 個資料夾:
DebugConfig:除錯設定資訊檔案(.dbgconf),不可刪除
Listings:編譯過程產生的連結列表等檔案
Objects:編譯過程產生的除錯資訊、 .hex、預覽、 .lib 檔案等->
先把 MDK 自動生成的這兩個資料夾(Listings 和 Objects)刪除

新增檔案:
設定工程名和分組名:設定工程名字為: 品->Template->
設定五個分組:
Startup(存放啟動檔案):Drivers\CMSIS\Device\ST\STM32F4xx\Source\Templates\arm
User(存放 main.c 等使用者程式碼)、
Drivers/SYSTEM(存放系統級驅動程式碼):Drivers\SYSTEM中的.c檔案
Drivers/STM32F4xx_HAL_Driver(hal庫檔案)、
Readme(存放工程說明檔案)->
新增啟動檔案:啟動檔案存放在 STM32CubeF4 軟體包的: Drivers\CMSIS\Device\ST\STM32F4xx\Source\Templates\arm\.s檔案->
啟動檔案主要作用:
1、堆疊(SP)的初始化;
2、初始化程式計數器(PC)
3、設定向量表異常事件的入口地址;
4、呼叫 main 函式等
->做了2 處修改:將 Heap_Size 改成 0;去掉 SystemInit呼叫->
Heap_Size EQU 0x00000000
; Reset handler
Reset_Handler PROC
				EXPORT Reset_Handler [WEAK]
				IMPORT __main
				LDR R0, =0xE000ED88 ;使能浮點運算 CP10,CP11
				LDR R1,[R0]
				ORR R1,R1,#(0xF << 20)
				STR R1,[R0]
				;暫存器版本程式碼,因為沒有用到 SystemInit 函式,所以註釋掉以下程式碼為防止報錯!
				;HAL 庫版本程式碼,建議加上這裡(外部必須實現 SystemInit 函式),以初始化
				;stm32 時鐘等.
				;IMPORT SystemInit
				;LDR R0, =SystemInit
				;BLX R0
				LDR R0, =__main
				BX R0
				ENDP

設定使用 FPU:魔術棒->Target1選項卡->Floating Point Hardware:Double Precision

魔術棒設定:
1,Target 選項卡:外部晶振頻率Xtal:看原理圖設定時脈頻率->ARM Compiler:Use default compiler version 5(即 AC5 編譯器)
2,Output 選項卡:Select Folder for Objects(選擇Objects輸出資料夾)->勾選"Create HEX File"
3,Listing 選項卡:Select Folder for Listing(選擇Objects輸出資料夾)
4,C/C++ 選項卡:
Define(設定全域性宏定義):USE_HAL_DRIVER,STM32F407xx->Optimization:Level 0(-O0)->勾選 C99 Mode->
Include Path:標頭檔案包含路徑設定
..\..\User
..\..\Drivers
..\..\Drivers\CMSIS\Device\ST\STM32F4xx\Include
..\..\Drivers\CMSIS\Include
..\..\Drivers\STM32F4xx_HAL_Driver\Inc
..\..\Middlewares
5,Debug 選項卡:Use:CMSIS-DAP Debugger->點選Settings->Debug->Port:SW--Max Clock:10NHz
6,Utilities 選項卡:點選Settings->點選Flash Download->勾選Reset and Run
7,Linker 選項卡(可選):取消勾選"Use ..."->Scatter File:..\..\User\SCRIPT\qspi_code.scf.scf

使用 AC6 編譯器,Misc Controls : -Wnoinvalid-source-encoding->
新增main.c->新增到分組->編譯會報錯修改stm32fxx_it.c新增標頭檔案#include "stm32f4xx_hal.h"