嵌入式開發中常見3個的C語言技巧

来源:http://www.cnblogs.com/CrazyCatJack/archive/2016/11/22/6080266.html
-Advertisement-
Play Games

Hey,大家好!我是CrazyCatJack。今天我來說幾個在嵌入式開發中常用的C語言技巧吧。也許你曾經用過,也許你只是見到過但是沒有深入理解。那麼今天好好補充下吧^_^ 1.指向函數的指針 指針不光能指向變數、字元串、數組,還能夠指向函數。在C語言中允許將函數的入口地址賦值給指針。這樣就可以通過指 ...


  Hey,大家好!我是CrazyCatJack。今天我來說幾個在嵌入式開發中常用的C語言技巧吧。也許你曾經用過,也許你只是見到過但是沒有深入理解。那麼今天好好補充下吧^_^

1.指向函數的指針

  指針不光能指向變數、字元串、數組,還能夠指向函數。在C語言中允許將函數的入口地址賦值給指針。這樣就可以通過指針來訪問函數。還可以把函數指針當成參數來傳遞。函數指針可以簡化代碼,減少修改代碼時的工作量。通過接下來的講解大家會體會到這一點的。

/*函數指針簡單講解
 *通過指向函數的指
 *針調用比較兩個數
 *大小的程式
 */

#include <iostream>
using namespace std;

/*比較函數聲明*/
int max(int,int);

/*指向函數的指針聲明(此刻指針未指向任何一個函數)*/
int (*test)(int,int);

int
main(int argc,char* argv[])
{
  int largernumber;

/*將max函數的入口地址賦值給
 *函數指針test
 */
  test=max;

/*通過指針test調用函數max實
 *現比較大小
 */
  largernumber=(*test)(1,2);
  cout<<largernumber<<endl;
  return 0;      
}

int
max(int a,int b)
{
   return (a>b?a:b);  
}

  通過註釋大家應該很容易理解,函數指針其實和變數指針、字元串指針差不多的。如果大家理解了這個小程式,那麼理解起下麵這個有關Nand flash的源代碼就好多了。

typedef struct {
    void (*nand_reset)(void);
    void (*wait_idle)(void);
    void (*nand_select_chip)(void);
    void (*nand_deselect_chip)(void);
    void (*write_cmd)(int cmd);
    void (*write_addr)(unsigned int addr);
    unsigned char (*read_data)(void);
}t_nand_chip;

static t_nand_chip nand_chip;

/* NAND Flash操作的總入口, 它們將調用S3C2410或S3C2440的相應函數 */
static void nand_reset(void);
static void wait_idle(void);
static void nand_select_chip(void);
static void nand_deselect_chip(void);
static void write_cmd(int cmd);
static void write_addr(unsigned int addr);
static unsigned char read_data(void);

/* S3C2410的NAND Flash處理函數 */
static void s3c2410_nand_reset(void);
static void s3c2410_wait_idle(void);
static void s3c2410_nand_select_chip(void);
static void s3c2410_nand_deselect_chip(void);
static void s3c2410_write_cmd(int cmd);
static void s3c2410_write_addr(unsigned int addr);
static unsigned char s3c2410_read_data();

/* S3C2440的NAND Flash處理函數 */
static void s3c2440_nand_reset(void);
static void s3c2440_wait_idle(void);
static void s3c2440_nand_select_chip(void);
static void s3c2440_nand_deselect_chip(void);
static void s3c2440_write_cmd(int cmd);
static void s3c2440_write_addr(unsigned int addr);
static unsigned char s3c2440_read_data(void);


/* 初始化NAND Flash */
void nand_init(void)
{
#define TACLS   0
#define TWRPH0  3
#define TWRPH1  0

    /* 判斷是S3C2410還是S3C2440 */
    if ((GSTATUS1 == 0x32410000) || (GSTATUS1 == 0x32410002))
    {
        nand_chip.nand_reset         = s3c2410_nand_reset;
        nand_chip.wait_idle          = s3c2410_wait_idle;
        nand_chip.nand_select_chip   = s3c2410_nand_select_chip;
        nand_chip.nand_deselect_chip = s3c2410_nand_deselect_chip;
        nand_chip.write_cmd          = s3c2410_write_cmd;
        nand_chip.write_addr         = s3c2410_write_addr;
        nand_chip.read_data          = s3c2410_read_data;

        /* 使能NAND Flash控制器, 初始化ECC, 禁止片選, 設置時序 */
        s3c2410nand->NFCONF = (1<<15)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0);
    }
    else
    {
        nand_chip.nand_reset         = s3c2440_nand_reset;
        nand_chip.wait_idle          = s3c2440_wait_idle;
        nand_chip.nand_select_chip   = s3c2440_nand_select_chip;
        nand_chip.nand_deselect_chip = s3c2440_nand_deselect_chip;
        nand_chip.write_cmd          = s3c2440_write_cmd;
#ifdef LARGER_NAND_PAGE
        nand_chip.write_addr         = s3c2440_write_addr_lp;
#else
        nand_chip.write_addr         = s3c2440_write_addr;
#endif
        nand_chip.read_data          = s3c2440_read_data;

        /* 設置時序 */
        s3c2440nand->NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);
        /* 使能NAND Flash控制器, 初始化ECC, 禁止片選 */
        s3c2440nand->NFCONT = (1<<4)|(1<<1)|(1<<0);
    }
    
    /* 複位NAND Flash */
    nand_reset();
}

  這段代碼是用於操作Nand Flash的一段源代碼。首先我們看到開始定義了一個結構體,裡面放置的全是函數指針。他們等待被賦值。然後是定義了一個這種結構體的變數nand_chip。然後是即將操作的函數聲明。這些函數將會被其他文件的函數調用。因為在這些函數里一般都只有一條語句,就是調用結構體的函數指針。接著往下看,是針對兩種架構的函數聲明。然後在nand_init函數中對nand_chip進行賦值,這也就是我們剛剛講過的,將函數的入口地址賦值給指針。現在nand_chip已經被賦值了。如果我們要對Nand進行讀寫操作,我們只需調用nand_chip.read_data()或者nand_chip.write_cmd()等等函數。這是比較方便的一點,另一點,此代碼具有很強的移植性,如果我們又用到了一種晶元,我們就不需要改變整篇代碼,只需在nand_init函數中增加對新的晶元的判斷,然後給nand_chip賦值即可。所以我說函數指針會使代碼具有可移植性,易修改性。

  如果大家想對函數指針有更深的理解建議看一下這篇博文:http://www.cnblogs.com/CBDoctor/archive/2012/10/15/2725219.html

  寫的超贊,博主很佩服^_^

 

2.C語言操作寄存器

  在嵌入式開發中,常常要操作寄存器,對寄存器進行寫入,讀出等等操作。每個寄存器都有自己固有的地址,通過C語言訪問這些地址就變得尤為重要。

#define GSTATUS1        (*(volatile unsigned int *)0x560000B0)

  在這裡,我們舉一個例子。這是一個狀態寄存器的巨集定義。首先,通過unsigned int我們能夠知道,該寄存器是32位的。因為要避免程式執行過程中直接從cache中讀取數據,所以用volatile進行修飾。每次都要重新讀取該地址上的值。首先(volatile unsigned int*)是一個指針,我們就假設它為p吧。它存儲的地址就是後面的0x560000B0,然後取這個地址的值,也就是*p,所以源代碼變成了(*(volatile unsigned int *)0x560000B0),接下來我們就能直接賦值給GSTATUS1來改變地址0x560000B0上存儲的值了。

/* NAND FLASH (see S3C2410 manual chapter 6) */
typedef struct {
    S3C24X0_REG32   NFCONF;
    S3C24X0_REG32   NFCMD;
    S3C24X0_REG32   NFADDR;
    S3C24X0_REG32   NFDATA;
    S3C24X0_REG32   NFSTAT;
    S3C24X0_REG32   NFECC;
} S3C2410_NAND;

static S3C2410_NAND * s3c2410nand = (S3C2410_NAND *)0x4e000000;

volatile unsigned char *p = (volatile unsigned char *)&s3c2410nand->NFSTAT;

  有時候,你會看到這樣一種情況的賦值。其實這和我們剛剛講過的差不多。只不過這裡是在定義了指針的同時對指針進行賦值。這裡首先定義了結構體S3C2410_NAND,裡面全部是32位的變數。又定義了這種結構體類型的指針,且指向0x4e000000這個地址,也就是此刻s3c2410nand指向了一個實際存在的物理地址。s3c2410nand指針訪問了NFSTAT變數,但我們要的是它的地址,而不是它地址上的值。所以用&取NFSTAT地址,這樣再強制轉換為unsigned char型的指針,賦給p,就可以直接通過p來給NFSTAT賦值了。

 

3.寄存器位操作

#define GPFCON      (*(volatile unsigned long *)0x56000050)
GPFCON &=~ (0x1<<3);
GPFCON |= (0x1<<3);

  結合我們剛剛所講的,首先巨集定義寄存器,這樣我們能夠直接給它賦值。位操作中,我們要學會程式第2行中的,給目標位清0,這裡是給bit3清0。第3行則是給bit3置1。

 

 

 

 

 

CCJ

2016-11-22 10:14:14


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 環境:Windows server2008r2 安裝mysql-connector-odbc-5.3.6-win32 報錯 相信錯誤信息:Error 1918.errror installing ODBC driver mysql ODBC 5.3 ANSI Drive 原因是缺少Microsoft ...
  • 恢復內容開始 學過之後卻沒有總結,今天好不容易有點時間來看看。 存儲過程的優勢 1.簡化複雜的SQL語句,將多個SQL語句封裝成為一個存儲過程,可以在其中加上一些流程式控制制語句 2.存儲過程封裝在資料庫內部,編譯之後直接調用,大大提高效率 3.模塊化編程,將一定功能的SQL語句封裝,提高可讀性 創建存 ...
  • 同步發佈:http://www.yuanrengu.com/index.php/mysqlsolvetimestamp.html 在使用mysql時,如果資料庫中的欄位類型是timestamp,預設為0000-00-00,會發生異常:Value ‘0000-00-00 00:00:00’ can n ...
  • DBMS_NETWORK_ACL_ADMIN學習 轉載 http://blog.sina.com.cn/s/blog_4f925fc30102e2se.html 標簽: oracle it 分類: 資料庫 http://docs.oracle.com/cd/B28359_01/appdev.111/ ...
  • 一、資料庫的簡介 什麼是資料庫? 數據的倉庫,如:在atm的實例中我們創建一個db目錄稱之為資料庫 什麼是 MySQL、Oracle、SQLite、Access、MS SQL Server等 ? 他們是資料庫軟體,主要功能為兩部分:1、講數據保存到記憶體或者文件。2、接受特定的命令對數據進行操作 什麼 ...
  • 使用PlateSpin複製出來的一資料庫伺服器(Oracle 10g)在啟動資料庫實例時遇到“ORA-00600: internal error code, arguments: [4194].....”錯誤,實例在啟動後,會自然Down掉。具體情況如下所示: Successfully online... ...
  • Windows環境配置MySQL集群 一、Cluster環境搭建 1、mysql Cluster(MySQL Cluster 7.5.4)文件下載地址:http://dev.mysql.com/downloads/cluster/ 2、準備三台伺服器(虛擬機,本人使用的是Windows Server ...
  • 1. 索引(Index) 索引是快速的定位和查找數據。索引分為: 聚集索引:唯一,預設主鍵,一般選取比較連貫的欄位,聚集索引是物理排序。 非聚集索引: 並沒有把數據物理排序,只是多了一個索引頁(包括索引項+存儲位置row number) a. 新建“非聚集索引” b. 選擇“專業”創建非聚集性索引。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...