娇小w搡bbbb搡bbb,《第一次の人妻》,中国成熟妇女毛茸茸,边啃奶头边躁狠狠躁视频免费观看

這節課我們來寫一個定時器的中斷服務程序

使用定時器來實現點燈計數

查考資料就是第10章PWM TIMER


我們先把這個結構圖展示出來

在這里插入圖片描述

這個圖的結構很好


這里面肯定有一個clk(時鐘),

1 、每來一個clk(時鐘)這個TCNTn減去1

2、 當TCNTn == TCMPn時,可以產生中斷,也可以讓對應的SPWM引腳反轉,(比如說原來是高電平,發生之后電平轉換成低電平)

3、 TCNTn繼續減1,當TCNTn == 0時,可以產生中斷,pwm引腳再次反轉 TCMPn 和 TCNTn的初始值來自TCMPBn,TCNTBn

4 、TCNTn == 0時,可自動加載初始


怎么使用定時器?

1、 設置時鐘

2 、設置初值

3、 加載初始,啟動Timer

4、 設置為自動加載

5 、中斷相關

由于2440沒有引出pwm引腳,所以pwm功能無法使用,也就無法做pwm相關實驗,所謂pwm是指可調制脈沖

T1高脈沖和T2低脈沖它的時間T1, T2可調整,可以輸出不同頻率不同占控比的波形,在控制電機時特別有用


我們這個程序只做一個實驗,當TCNTn這個計數器到0的時候,就產生中斷,在這個中斷服務程序里我們點燈


寫代碼

打開我們的main函數


int main(void)

{

    led_init();

    interrupt_init();  /* 初始化中斷控制器 */

//我們初始化了中斷源,同樣的,我們初始化timer

    key_eint_init();   /* 初始化按鍵, 設為中斷源 */

//初始化定時器

    timer_init();


我們需要實現定時器初始化函數

新建一個timer.c ,我們肯定需要操作一堆寄存器,添加頭文件


#include "s3c2440_soc.h"


void timer_init(void)


設置TIMER0的時鐘

設置TIMER0的初值

加載初值, 啟動timer0

設置為自動加載并啟動(值到0以后會自動加載)

設置中斷,顯然我們需要提供一個中斷處理函數void timer_irq(void)在這里面我們需要點燈

打開芯片手冊,我們想設置timer0的話

首先設置8-Bit Prescaler

設置5.1 MUX(選擇一個時鐘分頻)

設置TCMPB0和TCNTB0

設置TCONn寄存器

在這里插入圖片描述

看手冊上寫如何初始化timer

在這里插入圖片描述

把初始值寫到TCNTBn 和TCMPBn寄存器

設置手動更新位

設置啟動位

往下看到時鐘配置寄存器

在這里插入圖片描述

有個計算公式

Timer clk = PCLK / {(預分頻數)prescaler value+1} / {divider value(5.1MUX值)}

PCLK是50M

= 50000000/(99+1)/16

= 31250

也就是說我們得TCON是31250的話,從這個值一直減到0


   Prescaler0等于99

  TCFG0 = 99; /* Prescaler 0 = 99, 用于timer0,1 */  


TCFG1 MUX多路復用器的意思,他有多路輸入,我們可以通過MUX選擇其中一路作為輸出

在這里插入圖片描述

根據上面mux的值,我們要把MUX0 設置成0011

只需要設置這4位即可,先清零

再或上 0011 就是3


TCFG1 &= ~0xf;

TCFG1 |= 3; /* MUX0 : 1/16 */


再來看看初始值控制寄存器

在這里插入圖片描述

一秒鐘點燈太慢了 ,就讓0.5秒

TCNTB0 = 15625; /* 0.5s中斷一次 */


這個寄存器是用來觀察里面的計數值的,不需要設置


現在可以設置TCON來設置這個寄存器

在這里插入圖片描述

現在需要設置Timer0

在這里插入圖片描述

開始需要手工更新

TCON |= (1<<1); /* Update from TCNTB0 & TCMPB0 */

把這兩個值放到TCNTB0 和 TCMPB0中

在這里插入圖片描述

注意:這一位必須清楚才能寫下一位


設置為自動加載并啟動,先清掉手動更新位,再或上bit0 bit3


TCON &=~ (1<<1); 

TCON |= (1<<0) | (1<<3); /* bit0: start, bit3: auto reload */


設置中斷,顯然我們需要提供一個中斷處理函數void timer_irq(void)

在Timer里沒有看到中斷相關的控制器,我們需要回到中斷章節去看看中斷控制器,看看有沒有定時器相關的中斷

我們沒有看到更加細致的Timer0寄存器


當TCNTn=TCMPn時,他不會產生中斷,會發生脈沖的反轉,只有當TCNTn等于0的時候才可以產生中斷,我們之前以為這個定時器可以產生兩種中斷,那么肯定有寄存器中斷或者禁止兩種寄存器其中之一,那現在只有一種中斷的話,就相對簡單些

設置中斷的話,我們只需要設置中斷控制器

設置interrupu.c中斷控制器


*初始化中斷控制器 void interrupt_init(void) 

INTMSK &= ~((1<<0) | (1<<2) | (1<<5));


*把定時器相應的位清零就可以了,哪一位呢?


INTPND的哪一位? 

INT_TIMER0第10位即可 

在這里插入圖片描述

INTMSK &= ~(1<<10); /* enable timer0 int */


當定時器減到0的時候就會產生中斷,就會進到start.s這里一路執行do_irq


do_irq:

    /* 執行到這里之前:

     * 1. lr_irq保存有被中斷模式中的下一條即將執行的指令的地址

     * 2. SPSR_irq保存有被中斷模式的CPSR

     * 3. CPSR中的M4-M0被設置為10010, 進入到irq模式

     * 4. 跳到0x18的地方執行程序 

     */


    /* sp_irq未設置, 先設置它 */

    ldr sp, =0x33d00000


    /* 保存現場 */

    /* 在irq異常處理函數中有可能會修改r0-r12, 所以先保存 */

    /* lr-4是異常處理完后的返回地址, 也要保存 */

    sub lr, lr, #4

    stmdb sp!, {r0-r12, lr}  


    /* 處理irq異常 */

    bl handle_irq_c


    /* 恢復現場 */

    ldmia sp!, {r0-r12, pc}^  /* ^會把spsr_irq的值恢復到cpsr里 */



讓后進入irq處理函數中處理,處理這個irq

void handle_irq_c(void)

{

    /* 分辨中斷源 */

    int bit = INTOFFSET;


    /* 調用對應的處理函數 */


if(bit ==0 || bit == 2 || bit == 5)/*eint0,2,rint8_23*/

{

    key_eint_irq(bit);/*處理中斷,清中斷源EINTPEND*/

}else if(bit == 10)//如果等于10的話說明發生的是定時器中斷,這時候就調用我們得timer_irq

{

    timer_irq();

}


    /* 清中斷 : 從源頭開始清 */

    SRCPND = (1<    INTPND = (1<}


回到timer.c文件中,在這個定時器處理函數中我們需要點燈

void timer_irq(void)

{

    /* 點燈計數 循環點燈*/

    static int cnt = 0;

    int tmp;


    cnt++;


    tmp = ~cnt;

    tmp &= 7;

    GPFDAT &= ~(7<<4);

    GPFDAT |= (tmp<<4);

}


代碼寫完我們實驗一下,上傳代碼,在Makefile中添加timer.o,進行編譯

編譯后進行燒寫

發現燈已經開始閃

對程序進行改進


進入main函數中執行 timer_init();

還需要修改interrupt.c

初始化函數


void interrupt_init(void) 


還需要調用中斷處理函數


void handle_irq_c(void) 


每次添加一個中斷我都需要修改handle_irq這個函數,這樣太麻煩,我能不能保證這個interrupt文件不變,只需要在timer.c中引用即可,這里我們使用指針數組

在interrupt.c中定義函數指針數組


typedef void(*irq_func)(int); 


定義一個數組,我們來卡看下這里有多少項,一共32位,我們想把每一個中斷的處理函數都放在這個數組里面來,當發生中斷時,我們可以得到這個中斷號,讓后我從數組里面調用對應的中斷號就可以了


irq_func irq_array[32];


那么我們得提供一個注冊函數



void register_irq (int irq, irq_func fp)

{

    irq_array[irq] = fp;

    INTMASK &= ~(1 << irq)

}


以后我直接調用對應的處理函數


void handle_irq_c(void)

{

    /* 分辨中斷源 */

    int bit = INTOFFSET;



/* 調用對應的處理函數 */

irq_array[bit](bit);


    /* 清中斷 : 從源頭開始清 */

    SRCPND = (1<    INTPND = (1<}


//按鍵中斷初始化函數需要注冊


    /* 初始化按鍵, 設為中斷源 */

    void key_eint_init(void)

    {

    /* 配置GPIO為中斷引腳 */

    GPFCON &= ~((3<<0) | (3<<4));

    GPFCON |= ((2<<0) | (2<<4));   /* S2,S3被配置為中斷引腳 */


    GPGCON &= ~((3<<6) | (3<<22));

    GPGCON |= ((2<<6) | (2<<22));   /* S4,S5被配置為中斷引腳 */



    /* 設置中斷觸發方式: 雙邊沿觸發 */

    EXTINT0 |= (7<<0) | (7<<8);     /* S2,S3 */

    EXTINT1 |= (7<<12);             /* S4 */

    EXTINT2 |= (7<<12);             /* S5 */


    /* 設置EINTMASK使能eint11,19 */

    EINTMASK &= ~((1<<11) | (1<<19));


register_irq(0, key_eint_irq);

register_irq(2, key_eint_irq);

register_irq(5, key_eint_irq);

    }


在timer.c中也需要設置中斷


    void timer_init(void)

    {

    /* 設置TIMER0的時鐘 */

    /* Timer clk = PCLK / {prescaler value+1} / {divider value} 

                 = 50000000/(99+1)/16

                 = 31250

     */

    TCFG0 = 99;  /* Prescaler 0 = 99, 用于timer0,1 */

    TCFG1 &= ~0xf;

    TCFG1 |= 3;  /* MUX0 : 1/16 */


    /* 設置TIMER0的初值 */

    TCNTB0 = 15625;  /* 0.5s中斷一次 */


    /* 加載初值, 啟動timer0 */

    TCON |= (1<<1);   /* Update from TCNTB0 & TCMPB0 */


    /* 設置為自動加載并啟動 */

     TCON &= ~(1<<1);

     TCON |= (1<<0) | (1<<3);  /* bit0: start, bit3: auto reload */


       /* 設置中斷 */

        register_irq(10, timer_irq);

    }


把interrupt.c中按鍵的初始化放在最后面


我們來看看我們做了什么事情,

<1>我們定義了一個指針數組

typedef void(*irq_func)(int);

注:這里看不懂請參考typedef函數指針用法

這個指針數組里面放有各個指針的處理函數

irq_func irq_array[32];


當我們去初始化按鍵中斷時,我們給這按鍵注冊中斷函數

register_irq(0, key_eint_irq);

register_irq(2, key_eint_irq);

register_irq(5, key_eint_irq);


這個注冊函數會做什么事情,他會把這個數組放在注冊函數里面,同時使能中斷


void register_irq(int irq, irq_func fp)

{

    irq_array[irq] = fp;


    INTMSK &= ~(1<}

//我們的timer.c中


timer_init();

//也會注冊這個函數

    /* 設置中斷 */

    register_irq(10, timer_irq);


把這個中斷irq放在第10項里同時使能中斷,以后我們只需要添加中斷號,和處理函數即可,再也不需要修改函數

燒寫執行


我們從start.s開始看,

一上電從 b reset運行做一列初始化


.text

.global _start


_start:

    b reset          /* vector 0 : reset */

    ldr pc, und_addr /* vector 4 : und */

    ldr pc, swi_addr /* vector 8 : swi */

    b halt           /* vector 0x0c : prefetch aboot */

    b halt           /* vector 0x10 : data abort */

    b halt           /* vector 0x14 : reserved */



reset:

    /* 關閉看門狗 */

    ldr r0, =0x53000000

    ldr r1, =0

    str r1, [r0]


    /* 設置MPLL, FCLK : HCLK : PCLK = 400m : 100m : 50m */

    /* LOCKTIME(0x4C000000) = 0xFFFFFFFF */

    ldr r0, =0x4C000000

    ldr r1, =0xFFFFFFFF

    str r1, [r0]


    /* CLKDIVN(0x4C000014) = 0X5, tFCLK:tHCLK:tPCLK = 1:4:8  */

    ldr r0, =0x4C000014

    ldr r1, =0x5

    str r1, [r0]


    /* 設置CPU工作于異步模式 */

    mrc p15,0,r0,c1,c0,0

    orr r0,r0,#0xc0000000   //R1_nF:OR:R1_iA

    mcr p15,0,r0,c1,c0,0


    /* 設置MPLLCON(0x4C000004) = (92<<12)|(1<<4)|(1<<0) 

     *  m = MDIV+8 = 92+8=100

     *  p = PDIV+2 = 1+2 = 3

     *  s = SDIV = 1

     *  FCLK = 2*m*Fin/(p*2^s) = 2*100*12/(3*2^1)=400M

     */

    ldr r0, =0x4C000004

    ldr r1, =(92<<12)|(1<<4)|(1<<0)

    str r1, [r0]


    /* 一旦設置PLL, 就會鎖定lock time直到PLL輸出穩定

     * 然后CPU工作于新的頻率FCLK

     */




    /* 設置內存: sp 棧 */

    /* 分辨是nor/nand啟動

     * 寫0到0地址, 再讀出來

     * 如果得到0, 表示0地址上的內容被修改了, 它對應ram, 這就是nand啟動

     * 否則就是nor啟動

     */

    mov r1, #0

    ldr r0, [r1] /* 讀出原來的值備份 */

    str r1, [r1] /* 0->[0] */ 

    ldr r2, [r1] /* r2=[0] */

    cmp r1, r2   /* r1==r2? 如果相等表示是NAND啟動 */

    ldr sp, =0x40000000+4096 /* 先假設是nor啟動 */

    moveq sp, #4096  /* nand啟動 */

    streq r0, [r1]   /* 恢復原來的值 */


    bl sdram_init

    //bl sdram_init2     /* 用到有初始值的數組, 不是位置無關碼 */


    /* 重定位text, rodata, data段整個程序 */

    bl copy2sdram


    /* 清除BSS段 */

    bl clean_bss


    /* 復位之后, cpu處于svc模式

     * 現在, 切換到usr模式

     */

    mrs r0, cpsr         /* 讀出cpsr */

    bic r0, r0, #0xf     /* 修改M4-M0為0b10000, 進入usr模式 */

    bic r0, r0, #(1<<7)  /* 清除I位, 使能中斷 */

    msr cpsr, r0


    /* 設置 sp_usr */

    ldr sp, =0x33f00000


    ldr pc, =sdram

sdram:

    bl uart0_init

[1] [2]
關鍵字:S3c2440  ARM異常  中斷體系  定時器中斷 引用地址:S3c2440ARM異常與中斷體系詳解8---定時器中斷程序示例

上一篇:S3c2440ARM異常與中斷體系詳解2---CPU模式(Mode)狀態(State)
下一篇:S3c2440ARM異常與中斷體系詳解3---Thumb指令集程序示例

推薦閱讀

隨著科技進步和經濟的快速發展,服務型機器人逐漸走進人們生活,應用在家庭、安防、教育等場景中,并開辟廣闊的市場空間。據IFR的調研 ,服務機器人的潛力大于工業機器人,而在服務機器人中,家庭服務機器人增長較快。2015年全球家庭服務機器人的銷售額22億美元,同比增長16%。預計2015年至2018年全球家庭服務機器人市場年均增長率35.24%,高于服務機器人...
軟件選址避免了通信的復雜性 ,12C比spi要有優勢,任何一個微控制器都可以在I2C總線上作為主模式,同一時刻只能有兩個器件通信。4.應答式數據傳輸 保證數據傳輸的正確率。通信的過程:首先來一組起始信號,表示開始通信 。通信完成后來一個 停止信號,表示通信結束。中間為數據傳輸:每發8位的有效數據之后要對方來一個應答位。上圖中A表示應答。所以...
  耕種從始至終都是一件非常重要的事情,以前的社會大家都會耕種,自給自足,但是慢慢社會變得安逸,農民這個職業比起其他或許變得太累了,年輕人不愿意,老年人做不動,而且種植還有風險還得看天公作不作美。全球人口一直在上升,沒有耕種人們吃什么呢?如何使用更少的土地和更少的資源來種植更多的糧食成為了一個大問題。因此,研究人員和設備制造商...
9月9日,北京市人民政府發布了《北京市關于促進高精尖產業投資推進制造業高端智能綠色發展的若干措施》(以下簡稱:《措施》),旨在加快建設國際科技創新中心,落實《北京市“十四五”時期高精尖產業發展規劃》,促進產業基礎再造提升和產業鏈優化升級,推進制造業高端、智能、綠色發展。《措施》提出了鼓勵投資高精尖產業、建立重大項目統籌協調機制、建...

史海拾趣

問答坊 | AI 解惑

電子技術自立學習法

人的一生中使用自立學習法的時間最長,自己看書、自己動手就是自立學習法。1.具備基本條件事半功倍為了高效率運用自立學習法進行電子技術的學習,應該具備下列一些基本條件:①自主學習的信心和精神非常重要,這種學習過程中要時刻牢記靠“兩條腿 ...…

查看全部問答∨

TVS 管的測試 高手請進

請問規格為:P6KE6.8A的TVS管怎么去檢測其質量的好壞? 樣品檢測!!!…

查看全部問答∨

51匯編語言指令集 下載!

51匯編語言指令集很多書上有,但是有很多書沒有放在一起,每章一部分。還有些朋友有書沒帶在身邊,或是使用過,望了買本書又劃不來。把這個傳上來方便各位。[ip]…

查看全部問答∨

Cygwin下vivi和kernel編譯全攻略

最近打算設計新產品,在Friendly Arm買了一套Matrix5系統研究一下。發現用ARM-Linux開發似乎比較明智些! 但用Windows習慣了,還不太熟悉Linux,而且重裝RH9恐怕很費事。還是先用Win2000吧,Linux熟悉熟悉再說! 看見版上有個Cygwin,可以在Windo ...…

查看全部問答∨

電賽時候鍵盤的設計

本帖最后由 paulhyde 于 2014-9-15 09:25 編輯 正好找資料,看到了自己電設時的一個論文,覺得這個鍵盤的設計還是很滿意的。 一般大家在設計鍵盤的時候,使用4*4矩陣來擺放16個按鍵,如果改變下位置,也許考官會有比較好的印象分。同樣的,其他地 ...…

查看全部問答∨

LED背光技術需要解決技術難點分析

replyreload += \',\' + 371471;Timson,如果您要查看本帖隱藏內容請回復…

查看全部問答∨

做Wince 開發在深圳的工資如何?

我做Wince 的車載軟件有半年多了,工資一般!想問一下在深圳做Wince 開發的前景如何?希望大牛門說說自己的看法~…

查看全部問答∨

Window mobile Recorder

在手機上開發了一個錄音機程序,但在正在錄音過程中來電時,錄音自動停止,可是寫文件出現了錯誤(WriteFile函數中參數出錯)。請問怎么怎樣才能解決?謝謝。…

查看全部問答∨

關于WINCE上的SKYPE給小弟一點幫助呀

是這樣的,我想在windows ce上的運行SKYPE程序?哪位兄弟有沒有移植好的EXE文件,或者源碼呀,能不能給我一份呀?小弟不勝感謝!我的郵箱是sunboyljp@163.com…

查看全部問答∨
小廣播
設計資源 培訓 開發板 精華推薦

最新單片機文章
何立民專欄 單片機及嵌入式寶典

北京航空航天大學教授,20余年來致力于單片機與嵌入式系統推廣工作。

 
EEWorld訂閱號

 
EEWorld服務號

 
汽車開發圈

 
機器人開發圈

電子工程世界版權所有 京ICP證060456號 京ICP備10001474號-1 電信業務審批[2006]字第258號函 京公網安備 11010802033920號 Copyright ? 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
主站蜘蛛池模板: 大丰市| 砀山县| 济宁市| 揭西县| 万载县| 马公市| 石柱| 梁山县| 孟村| 丰宁| 务川| 博乐市| 公主岭市| 昭平县| 台东市| 吕梁市| 漳平市| 建水县| 彰化县| 高阳县| 双城市| 大安市| 池州市| 儋州市| 邛崃市| 凯里市| 嘉黎县| 托克逊县| 莱西市| 祁门县| 定南县| 南开区| 洮南市| 亚东县| 富平县| 禄丰县| 滕州市| 中超| 申扎县| 福建省| 措勤县|