1. 程式人生 > >[筆記]|[stm32]|[暫存器儲存器區別]|[PWM]|[串列埠]|[Timer]stm32f103筆記

[筆記]|[stm32]|[暫存器儲存器區別]|[PWM]|[串列埠]|[Timer]stm32f103筆記

[筆記]|[stm32]|[暫存器儲存器區別]|[PWM]|[串列埠]|[Timer]stm32f103筆記

此筆記為18.12.21筆者期末複習所寫 ——僅作為自己期末複習以及過後查閱的資料

文章目錄

微控制器與嵌入式系統

  1. 微控制器(英文縮寫MCU

  2. 微控制器只是嵌入式CPU的稱呼(微控制器可以理解為CPU)(嵌入式可有多個CPU)

  3. 微控制器的特點是只有一個控制單元

  4. 嵌入式和普通的計算機核心區別在資源共享問題上

  5. 嵌入式可分為軟體硬體組成

    • 硬體部分主要有以下組成:

      1. mpu
        為核心的組成,如:arm等
      2. mcu為核心,就是各種各樣的微控制器,它主要是因為把處理器和儲存器等部件整合在一塊晶片上。
      3. dsp為核心,主要用來處理語音圖形方面。
      4. 就是人們所說的sop了。
    • 軟體部分主要是:

      有的嵌入式有作業系統,有的沒有。主要是由系統大小決定。

CPU、MCU、MPU、DSP的區別?

  • CPU:

    CPU(Central Processing Unit,中央處理器)發展出來三個分枝,一個是DSP(Digital Signal
    Processing/Processor,數字訊號處理

    ),另外兩個是MCU(Micro Control Unit,微控制器單元)和MPU(Micro Processor Unit,微處理器單元)。

  • MCU:

    MCU集成了片上外圍器件;MPU不帶外圍器件(例如儲存器陣列),(MCU)是高度整合的通用結構的處理器,是去除了整合外設的MCU;DSP運算能力強,擅長很多的重複資料運算,而MCU則適合不同資訊源的多種資料的處理診斷和運算,(MCU)側重於控制,速度並不如DSP。

  • MCU區別於DSP的最大特點在於它的通用性,反映在指令集和定址模式中。DSP與MCU的結合是DSC

微控制器的基本工作原理

程式(命令的集合) -> 儲存到儲存器中(留下所分配的地址號) -> 使用時地址被取出 -> 被執行

微控制器的幾個重要概念

  1. 匯流排:用於地址分配的線也較多(儲存單元多),這些線被稱為地址匯流排。
  2. 資料、地址、指令:都是‘0’和‘1’的組成的序列
  3. 功能複用,功能模組的初始化、驅動。
  4. 程式的執行過程。
  5. 開發環境的建立

stm32微控制器簡介

  1. Cortex-M3核心
  2. 標準的ARM架構
  3. 高效能
  4. 低電壓
  5. 低功耗
  6. 電壓範圍2.0到3.6V
  7. I/O電壓容限為5V

stm32程式編寫基本步驟

  1. 初始化管腳
  2. 初始化功能模組
  3. 編寫硬體測試程式碼
  4. 實現功能,除錯,修改

巢狀中斷向量控制器

巢狀中斷向量控制器(Nested Vector Interrupt Controller,簡稱NVIC)它基於Cortex-M3的微控制器提供了標準的中斷架構和優秀的中斷響應能力超過240個中斷源提供專門的中斷入口,而且可以賦予每個中斷源單獨的優先順序。利用NVIC從可以達到極快的中斷響應速度,從收到中斷請求到執行中斷服務的第一條指令僅需12個週期。這種極快的響應速度一方面得益於Cortex-M3核心對堆疊的自動處理機制,這種機制是通過固化在CPU內部的微程式碼實現的。另一方面,在中斷請求連續出現的情況下,NVIC使用一種稱為**“尾鏈”**的技術,使連續而來的中斷可以在6個時鐘週期內得到服務。在中斷的壓棧階段,更高優先順序的中斷可以不耗費任何額外的CPU週期就能完成嵌入低優先順序中斷的動作。具體的細節後面我會繼續總結的。使用者可以通過設定CPU自動進入低功耗狀態,而使用中斷來將其喚醒,CPU在中斷時間來臨之前會一直保持睡眠狀態。

暫存器與儲存器的區別

一般意義上理解,暫存器是CPU裡的儲存單元,與CPU離得近,所以CPU在運算時通常都會用暫存器當中轉站。儲存器是在CPU外部的儲存器,分為RAM,ROM
對微控制器來說,因為儲存器,CPU都在一個片內,所以暫存器是片內RAM的一部分。

也就是說微控制器的儲存器包括暫存器

序列通訊

  1. 計算機通訊:通訊分為並行通訊與序列通訊兩種基本方式。
    • 並行通訊:將資料的各位用多條資料線同時進行傳送,外加地址線和通訊控制線。(多條資料線+地址線+通訊控制線)
    • 序列通訊:將資料分成1位1位的形式在一條傳輸線上逐個地傳送
    • 特殊的序列通訊:4位序列

圖片1

  1. 並行通訊和序列通訊:

    • 並行通訊常用於積體電路晶片的內部同一外掛板上各部件之間同一機箱內各外掛板之間的資訊互動

    • 序列通訊常用於裝置之間的資訊互動

      圖片4

  2. 同步通訊和非同步通訊

    • 根據資料傳輸方式的不同,可將序列通訊分為同步通訊和非同步通訊序列通訊常用於裝置之間的資訊互動
    • 非同步通訊:若接收端與傳送端使用的不是同一時鐘訊號(但必須同頻率),則為非同步通訊。以字元為單位,一個字元一個字元地傳送,並且每一個字元要有起始符和停止符作為開始和結束的標誌。(一個字元就是一幀)常見的是USART(串列埠)
    • 同步通訊是一種資料連續傳輸的序列通訊方式,通訊時傳送方把需要傳送的多個位元組資料和校驗資訊連線起來,組成資料塊。傳送時,傳送方只需在資料塊前插入1~2個特殊的同步字元,然後按特定速率逐位輸出(傳送)資料塊內的各位資料。接收方在接收到特定的同步字元後,也按相同速率接收資料塊內的各位資料。(常見的有IIC,SPI等)
  3. 序列通訊的工作方式

    1. 單工方式:這種方式只允許資料按一個固定的方向傳輸。資料傳輸僅能從傳送裝置傳輸到接收裝置
    2. 半雙工方式:資料可以從A傳送到B,也可以由B傳送到A但A、B之間只有一根傳輸線,因此同一時刻只能作一個方向的傳送。其傳送方向由收發控制開關K切換平時一般讓A、B方都處於接收狀態,以便能夠隨時響應對方的呼叫。兩個序列通訊裝置之間只有一條資料線,資料傳輸可以沿兩個方向,但需要分時進行
    3. 全雙工方式資料可同時在兩個方向上傳送
  4. 串列埠與RS232、RS485、RS422(屬於物理層知識)

    • RS422是差分全雙工(4線),RS232是雙工(3線),RS485是半雙工(2線)
  5. 波特率

    • 單位:bps(bit per second)

    • 定義:每秒鐘傳送的二進位制位數

    • Baudrate(波特率範圍):50 ~ 19200 ~ 57600

      ​ 50,100,150,300,600,1200,2400,
      ​ 4800,9600,19200,38400,57600,115200

    • 如每秒傳送240個字元,而每個字元格式包含10位這時的波特率為10位(bit)×240個/s = 2400 bit/s。

    • 在非同步序列通訊中,接收方和傳送方應使用相同的波特率,才能成功傳送資料

  6. STM32的串列埠

    • 一般意義上我們所說的串列埠指的是USART。SPI,IIC都會特別指出。
    • 至少有3個串列埠,根據具體的型號有所不同。
    • 1號串列埠可以下載程式用。
    • 使用串列埠首先要使能IO時鐘串列埠模組時鐘初始化IO初始化串列埠
    • 有關串列埠的高階使用:中斷串列埠重定向

除錯手段

  1. 設定斷點,設定斷點的技巧:

    在程式執行的程式碼中可以設定斷點,程式執行到斷點處即停止,但是斷點處不見得就是問題出現的時刻。需要根據猜測設定需要進入的條件。

  2. 串列埠日誌輸出

    在程式執行的過程中可以通過串列埠將執行過程中的一些關鍵變數輸出以得知程式執行的狀態是否正確。

  3. 通過外界輸入一些資訊,影響程式執行的狀態,觀察執行的輸出以測試程式執行是否正常

中斷

  1. 什麼是“中斷”?

    圖片6

    • CPU執行程式時,由於發生了某種隨機的事件(外部或內部),引起CPU暫時中斷正在執行的程式,轉去執行一段特殊的服務程式(中斷服務子程式或中斷處理程式),以處理該事件,該事件處理完後又返回被中斷的程式繼續執行 ,這一過程稱為中斷。

​ EG:吃飯時突然手機鈴響…

  1. STM32中的優先順序概念

    • STM32(Cortex-M3)中有兩個優先順序的概念:搶佔式優先順序響應優先順序,也把響應優先順序稱作“亞優先順序”或“副優先順序”,每個中斷源都需要被指定這兩種優先順序。
      1. 何為佔先式優先順序(pre-emption priority)
        • 高佔先式優先順序的中斷事件會打斷當前的主程式/中斷程式執行—搶斷式優先響應,俗稱中斷巢狀
      2. 何為副優先順序(subpriority)
        • 佔先式優先順序相同的情況下,高副優先順序的中斷優先被響應
        • 佔先式優先順序相同的情況下,如果有低副優先順序中斷正在執行,高副優先順序的中斷要等待已被響應的低副優先順序中斷執行結束後才能得到響應非搶斷式響應(不能巢狀)
  2. stm32中對中斷優先順序的定義

    • STM32中指定中斷優先順序的暫存器位有4位,這4個暫存器位的分組方式如下:
    • 第0組:所有4位用於指定響應優先順序

    • 第1組:最高1位用於指定搶佔式優先順序,最低3位用於指定響應優先順序

    • 第2組:最高2位用於指定搶佔式優先順序,最低2位用於指定響應優先順序

    • 第3組:最高3位用於指定搶佔式優先順序,最低1位用於指定響應優先順序

    • 第4組:所有4位用於指定搶佔式優先順序

      圖片21

  3. stm32的串列埠接收中斷

    • 步驟一:初始化GPIO
    • 步驟二:開時鐘
    • 步驟三:初始化USART1
    • 步驟四:編寫中斷函式
    • void USART1_IRQHandler(void)

八段碼

  1. 八段碼(數碼管)的基本概念

    圖片12

    圖片13

  2. stm32的八段碼使用

    • 步驟一:初始化GPIO
    • 步驟二:開時鐘
    • 步驟三:初始化USART1
    • 步驟四:編寫中斷函式 void USART1_IRQHandler(void)
    • 步驟五: 找段
    • 步驟六:換碼

定時器

  1. stm32的定時器

    • STM32一共有8個通用16位Timer,其中TIMER1和TIMER8是高階定時器,其它的TIMER2~TIMER7是普通定時器
    • 此外還有一個Systick(系統滴答定時器),這個定時器通常在作業系統中作為系統的任務切換週期
    • 還有一個RTC,是一個毫秒定時器,支援秒級中斷用來做實時時鐘計數器
    • 看門狗定時器 也可以算一個。
    • 8個定時器中,Timer1和Timer8是由APB2(輸出最高頻率為72MHZ)預分頻後,再通過一個倍頻器得到時鐘頻率,最高為72MHzTimer2~Timer7則是由APB1(輸出最高頻率為36MHZ)預分頻後,再通過一個倍頻器得到時鐘頻率,最高為36MHz
  2. Systick(系統滴答定時器)

    1. //初始化:
      void Delay_Init(u8 SYSCLK)
         {
           SysTick->CTRL &=~BIT(2);//關定時器
      	 SysTick->CTRL &=~BIT(1);//關閉中斷請求
      	 fac_us = SYSCLK/8;		//計算延時係數
      	 fac_ms = (u16)fac_us*1000;	 
          }
      
    2. //延時函式: 
      void delay_us(u32 nus)
      {		
      	SysTick->LOAD = (u32)fac_us*nus-1;//載入延時引數	 
          SysTick->VAL = 1;				//重置計數暫存器(初始化)
      	SysTick->CTRL |= BIT(0);		//開定時器(SysTick使能)
      	while(!(SysTick->CTRL&(1<<16)));//等待計數到0(判斷是否到零)
      	SysTick->CTRL &=~BIT(0);//關SysTick(關閉)
      }
      
    3. //延時函式定義:
      void Delay(__IO uint32_t nTime)
                                   { 
                                       	TimingDelay = nTime; 
                                        	while(TimingDelay != 0);
                                     }
      
    4. systick也有中斷入口也可以使用中斷方式進行延時,具體程式碼可下自行研究。

  3. stm32的通用定時器

    • TIM2-TIM5普通定時器的定時功能。
    • 程式設計步驟
        1. 配置系統時鐘;
        1. 配置NVIC;
        1. 配置GPIO;
        1. 配置TIMER;
    • 配置:
      • (1) 利用TIM_DeInit()函式將Timer設定為預設預設值;
      • (2) TIM_InternalClockConfig()選擇TIMx來設定內部時鐘源; //可省略
      • (3) TIM_Perscaler來設定預分頻係數;
      • (4) TIM_ClockDivision來設定時鐘分割;
      • (5) TIM_CounterMode來設定計數器模式;
      • (6) TIM_Period來設定自動裝入的值
      • (7) TIM_ARRPerloadConfig()來設定是否使用預裝載緩衝器 //可省略
      • (8) TIM_ITConfig()來開啟TIMx的中斷
      • 其中(3)-(6)步驟中的引數由TIM_TimerBaseInitTypeDef結構體給出。步驟(3)中的預分頻係數用來確定TIMx所使用的時鐘頻率,具體計算方法為:CK_INT/(TIM_Perscaler+1)。CK_INT是內部時鐘源的頻率,是根據2.1中所描述的APB1的倍頻器送出的時鐘,TIM_Perscaler是使用者設定的預分頻係數,其值範圍是從0
        – 65535。
      • 步驟(7)中需要禁止使用預裝載緩衝器。當預裝載緩衝器被禁止時,寫入自動裝入的值(TIMx_ARR)的數值會直接傳送到對應的影子暫存器;如果使能預載入暫存器,則寫入ARR的數值會在更新事件時,才會從預載入暫存器傳送到對應的影子暫存器。
  4. stm32的TIM2初始化

    void TIMER_cfg() 
    {
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; //定義timer結構體變數
    
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); //TIM 2-7在匯流排1上面
    
    //重新將Timer設定為預設值。。
    TIM_DeInit(TIM2); 
    
    //採用內部時鐘給TIM2提供時鐘源,
    // TIM_InternalClockConfig(TIM2); //源程式 有這個,但是去掉 也無妨
    
    //預分頻係數為36000-1,這樣計數器時鐘為36MHz/36000 = 1kHz
    TIM_TimeBaseStructure.TIM_Prescaler = 36000 - 1;
    //設定時鐘分割
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    //設定計數器模式為向上計數模式
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    //設定計數溢位大小,每計2000個數就產生一個更新事件
    TIM_TimeBaseStructure.TIM_Period = 2000 - 1;
    //將配置應用到TIM2中
    TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);
    
    //清除溢位中斷標誌
    TIM_ClearFlag(TIM2, TIM_FLAG_Update);
    //禁止ARR預裝載緩衝器
    // TIM_ARRPreloadConfig(TIM2, DISABLE);
    //開啟TIM2的中斷
    TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
    
    TIM_Cmd(TIM2,ENABLE);
    }
    
  5. stm32的TIM2定時器中斷函式

    void NVIC_cfg()
    {
    NVIC_InitTypeDef NVIC_InitStructure;
    //選擇中斷分組1
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
    
    
    //選擇TIM2的中斷通道
    NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; 
    //搶佔式中斷優先順序設定為0
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    //響應式中斷優先順序設定為0
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    //使能中斷
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure); //初始化
    }
    
    void TIM2_IRQHandler(void)
    {
    u8 ReadValue;
    //檢測是否發生溢位更新事件
    if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
    {
    //清除TIM2的中斷待處理位
    TIM_ClearITPendingBit(TIM2 , TIM_FLAG_Update);
    //將PB.5管腳輸出數值寫入ReadValue
    ReadValue = GPIO_ReadOutputDataBit(GPIOD,GPIO_Pin_13);
    if(ReadValue == 0)
    {
    GPIO_SetBits(GPIOD,GPIO_Pin_13);
    } 
    else
    {
    GPIO_ResetBits(GPIOD,GPIO_Pin_13); 
    }
    }
    }
    

通訊協議(串列埠)

  1. 通訊協議:

    1. 通訊協議或簡稱為傳輸協議(Communications Protocol)在電信中,是指在任何物理介質中允許兩個或多個在傳輸系統中的終端之間傳播資訊的系統標準,也是指計算機通訊或網路裝置的共同語言。[1], 通訊協議定義了通訊中的語法學, 語義學和同步規則以及可能存在的錯誤檢測與糾正。通訊協議在硬體,軟體或兩者之間皆可實現[2]為了交換大量資訊,通訊系統使用通用格式(協議)。每條資訊都有明確的意義使得預定位置給予響應,並獨立生效回饋指定行為,通訊協議須參與實體都同意才能生效

    2. 通訊協議又稱通訊規程,是指通訊雙方對資料傳送控制的一種約定。約定中包括對資料格式同步方式傳送速度傳送步驟檢糾錯方式以及控制字元定義等問題做出統一規定,通訊雙方必須共同遵守,它也叫做鏈路控制規程

  2. 通訊協議的要素:

    1. 包頭
    2. 包尾
    3. 地址
    4. 解析
  3. 通訊協議處理設計思想

    1. 命令快取區 buffer
    2. 分幀
    3. 命令處理

硬體pwm

  1. 硬體pwm基本原理

    • pwm由定時器產定時器的定時時間決定了pwm的頻率

    • 比較暫存器決定了pwm的佔空比

      (比較暫存器,作用是其中寄存了與計數暫存器相比較的值,當兩個值相等時,發生一次比較跳變,輸出的pwm波跳變

    • 定時器與輸出pwm的管腳之間是有約束關係的

  2. pwm初始化

     //第一步:配置時鐘               
     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_T  IM1,ENABLE);
     //第二步,配置goio口          
        GPIO_InitStructure2.GPIO_Pin=GPIO_Pin_8;         
     GPIO_InitStructure2.GPIO_Speed=GPIO_Speed_50MHz;         
     GPIO_InitStructure2.GPIO_Mode=GPIO_Mode_Out_PP;           //設定為複用浮空輸出         
     GPIO_Init(GPIOA,&GPIO_InitStructure2 GPIO_InitStructure2.GPIO_Pin=GPIO_Pin_13;         
     GPIO_InitStructure2.GPIO_Speed=GPIO_Speed_50MHz;         
     GPIO_InitStructure2.GPIO_Mode=GPIO_Mode_Out_PP;            //設定為複用浮空輸出         
     GPIO_Init(GPIOB,&GPIO_InitStructure2);
     //第三步,定時器基本配置         
     TIM_TimeBaseStructure.TIM_Period=1000-1;                   // 自動重灌載暫存器的值        
     TIM_TimeBaseStructure.TIM_Prescaler=72-1;                  // 時鐘預分頻數        
     TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;      // 取樣分頻        
     TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;  //向上計數        
     TIM_TimeBaseStructure.TIM_RepetitionCounter=0;      //重複暫存器,用於自動更新pwm佔空比                       
     TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
               
     //第四步pwm輸出配置         
     TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM2;  //設定為pwm1輸出模式         
     TIM_OCInitStructure.TIM_Pulse=500;                                 //設定佔空比時間         
     TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_Low;    //設定輸出極性         
     TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;        //使能該通道輸出          
     //下面幾個引數是高階定時器才會用到,通用定時器不用配置         
     TIM_OCInitStructure.TIM_OCNPolarity=TIM_OCNPolarity_High;        //設定互補端輸出極性         
     TIM_OCInitStructure.TIM_OutputNState=TIM_OutputNState_Enable;//使能互補端輸出         
     TIM_OCInitStructure.TIM_OCIdleState=TIM_OCIdleState_Reset;        //死區後輸出狀態         
     TIM_OCInitStructure.TIM_OCNIdleState=TIM_OCNIdleState_Reset;//死區後互補端輸出狀態         
     TIM_OC1Init(TIM1,&TIM_OCInitStructure);                                            //按照指定引數初始化           
     //第五步,死區和剎車功能配置,高階定時器才有的,通用定時器不用配置         
     TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Disable;//執行模式下輸出
     TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Disable;//空閒模式下輸出選擇          
     TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_OFF;  //鎖定設定        
     TIM_BDTRInitStructure.TIM_DeadTime = 0x90;              //死區時間設定         
     TIM_BDTRInitStructure.TIM_Break = TIM_Break_Disable;      //剎車功能使能         
     TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High;//剎車輸入極性        
     TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;
     //自動輸出使能          
     TIM_BDTRConfig(TIM1,&TIM_BDTRInitStructure);
     //第六步,使能端的開啟 
     TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);  //使能TIMx在CCR1上的預裝載暫存器         
     TIM_ARRPreloadConfig(TIM1, ENABLE); //使能TIMx在ARR上的預裝載暫存器         
     TIM_Cmd(TIM1,ENABLE);                              //開啟TIM2         
     
     //下面這句是高階定時器才有的,輸出pwm必須開啟         
     TIM_CtrlPWMOutputs(TIM1, ENABLE);                                   
     //pwm輸出使能,一定要記得開啟
    
     // 在運行當中想要改變pwm的頻率和佔空比呼叫:
     TIM_SetAutoreload(TIM1,1000); 
     TIM_SetCompare1(TIM1,500);
               
      //下面這句是高階定時器才有的,輸出pwm必須開啟         
     TIM_CtrlPWMOutputs(TIM1, ENABLE);                                   //pwm輸出使能,一定要記得開啟
    
     // 在運行當中想要改變pwm的頻率和佔空比呼叫:
     TIM_SetAutoreload(TIM1,1000); 
     TIM_SetCompare1(TIM1,500);