嵌入式linux——點亮led燈(二)


  剛才在jz2440板子上寫了一個點亮中間led的程序,前前后后十幾分鍾才好。最終代碼

本節內容:

  1. 匯編點燈

  2. C點燈

  3. 參數選擇點燈

  4. 按鍵點燈

1. 匯編點燈

.text
.global _start

_start:
/* 在這個程序中,完成點亮中間的led燈D11
 *  GPF5 從原理圖得知,低電平點亮
 * GPFCON  0x56000050 
 * GPFDAT  0x56000054
 
 */
    ldr r0, =0x56000050
    ldr r1, =0x400
    str r1, [r0]

    mov r0, #0
    ldr r1, =0x56000054
    str r0, [r1]
halt:
    b halt

makefile如下

all:
    arm-linux-gcc -c -o led_on.o led_on.S
    arm-linux-ld -Ttext 0 led_on.o -o led_on.elf
    arm-linux-objcopy -O binary -S led_on.elf led_on.bin
    arm-linux-objdump -D led_on.elf > led_on.dis
clean:
    rm *.bin *.o *.elf

這個點燈程序還是比較簡單的,在原理圖上找到led連接的io口,在看一下高低電平點亮。

然后,往配置寄存器地址里面寫配置io口的配置輸出。往數據寄存器地址寫入輸出高低電平,即可。

在makefile文件中,用arm-linux-gcc編譯器:.s -> .o -> .elf -> .bin 就有了bin文件可以燒到板子上看一下現象。

 

 2. C點燈

  剛才又寫了兩個程序。第一個,是用c程序點燈,匯編和c文件代碼如下

.text
.global _start

_start:

    ldr sp, =4096  

    /* 調用c函數點燈*/
    bl main

halt:
    b halt
int main()
{
    unsigned int *pGPFCON = (unsigned int *)0x56000050;
    unsigned int *pGPFDAT = (unsigned int *)0x56000054;
    
    *pGPFCON = 0x400;
    *pGPFDAT = 0;
    
    return 0;

}

點燈的功能在c文件中實現,但是調用c函數之前,需要設置棧,因為1)c程序的變量保存在棧中;2)調用c函數之前,要保存當前狀態,保存在棧中。所以要設置好棧,就是sp寄存器。本代碼只適應於nand啟動,不適合nor啟動,后面會補上,片內SRAM有4k,用作棧。

匯編中直接用bl xxx,就可以直接調用c文件中的函數 xxx 函數,c文件中實現點燈。

 

3. 參數選擇點燈

第二個是在匯編文件中調用c函數時,傳入參數,選擇點亮那個led燈。

.text
.global _start

_start:

    ldr sp, =4096  /* nand啟動 */

    mov r0, #1
    bl main

halt:
    b halt

 

 

int main(int lednum)
{
    unsigned int *pGPFCON = (unsigned int *)0x56000050;
    unsigned int *pGPFDAT = (unsigned int *)0x56000054;
    
    
    if (lednum == 1)
    {
        *pGPFCON = 0x100;
        *pGPFDAT = 0;
        return 0;        
    }
    if (lednum == 2)
    {
        *pGPFCON = 0x400;
        *pGPFDAT = 0;
        return 0;        
    }    
    if (lednum == 3)
    {
        *pGPFCON = 0x1000;
        *pGPFDAT = 0;
        return 0;        
    }
}

在匯編文件中調用c函數,用r0,r1,r2寄存器傳入第一個、第二個、第三個參數,在c文件中正常接收即可,return位置可以在最后,但是這么寫的話,可以少判斷兩條語句(如果第一條就返回)。

 

 

4. 按鍵點燈,剛才寫了按鍵的點燈程序。功能:一個按鍵,一個led。按鍵按下,燈就亮,松開就滅。一共有三段程序,如下:

int main(int lednum)
{
    unsigned int *pGPFCON = (unsigned int *)0x56000050;
    unsigned int *pGPFDAT = (unsigned int *)0x56000054;
    
    unsigned int *pGPGCON = (unsigned int *)0x56000060;
    unsigned int *pGPGDAT = (unsigned int *)0x56000064;    
    
    // GPF4 ouput,先清位,再置為
    *pGPFCON &= ~(3<<8) ;
    *pGPFCON |=   (1<<8) ;

    // GPF0 is input
    *pGPFCON &= ~(3<<0);
    *pGPGDAT &= ~(3<<6);
    
    *pGPFDAT = 0XFF;
        
    while ( 1 )
    {         
// 第一段代碼:實現按下兩 ,松開滅
/*         if ( *pGPFDAT & ((1<<0)) )        
            *pGPFDAT |= (1<<4);   // 沒按下 滅
        
        else
            *pGPFDAT &= ~(1<<4);  // 按下 on
 */        
// 第二段代碼:上電亮,按鍵無反應, (~(1<<0)) 不是0,所以不能用來判斷
// 按鍵1,是GPF0,上面初始是FF,1111 1111,(1<<0) 是 0000 0001 取反是 1111 1110  與操作后,無論是否有按鍵按下,肯定是非0,真,執行當作按鍵按下,燈亮
/*         if ( *pGPFDAT & (~(1<<0)) )        
            *pGPFDAT &= ~(1<<4);   // 按下亮
        
        else
            *pGPFDAT |= (1<<4);  //  沒按下滅
 */
 
 // 第三段代碼:實現按下亮,松開滅
        if ( !(*pGPFDAT & (1<<0)) )        
            *pGPFDAT &= ~(1<<4);   // 按下亮        
        else
            *pGPFDAT |= (1<<4);  //  沒按下滅
    }
    return 0;
}

一共有三段代碼,一三可以是實現功能,到那時第二段不可以,想了好半天,才發現問題,寫在了注釋了,以后,判斷某位置的話,用第一種比較好,三有些麻煩。

 

 

之后還要寫一個,按一下亮,再按一下滅的程序

 

總結:

1. 調用C函數之前要設置棧

2. 匯編調用C函數用r0,r1等寄存器傳送參數。

3. 判斷寄存器某位0或1的方法。rxx & (yy << zz)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM