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

歷史上的今天

今天是:2025年05月31日(星期六)

2019年05月31日 | 從自定義的庫函數到STM32官方標準庫

發布者:RadiantRiver 來源: eefocus關鍵字:自定義  庫函數  STM32  官方標準 手機看文章 掃描二維碼
隨時隨地手機看文章

??在上一節的基礎上,進一步改寫代碼,再引入官方標注庫函數。雖然官方標準庫慢慢式微,有一些別的庫可能會取代它,但是并不妨礙我們繼續拿官方庫來寫代碼,吸取里邊好的寫法,強化下C語言技能,加深對寄存器的理解也是不錯的。

  本文模仿庫函數,首先自定義庫函數,然后一步一步改寫代碼,最終引入官方標準庫函數。


實現流水燈

void delay(unsigned int a)

{

    while(a--);

}


int main(void)

{

    RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;

    GPIOB->CRH &= ~(0xf<<(0*4)|0xf<<(1*4));

    GPIOB->CRH |= 0x3<<(0*4)|0x3<<(1*4);    

    while(1)

    {   

        GPIOB->ODR &= ~(1<<8);  //PB8 = 0

        GPIOB->ODR |= 1<<9;         //PB9 = 1

        delay(0xfffff);

        GPIOB->ODR &= ~(1<<9);   //PB9 = 0

        GPIOB->ODR |= 1<<8;      //PB8 = 1

        delay(0xfffff);

    }    

}



??主要是增加了延時函數與while(1)的循環。通過寄存器,實現流水燈。這是單片機最基礎的實驗,意義等同于helloworld。這些代碼如果有51基礎,是很好理解的。但是存在問題:代碼的擴展性與維護性較差,存在較多的復制粘貼,不太容易看懂,如果出現業務變更,如LED的引腳換了,那么修改工作太大。

??接下來我們來自己從零開始,寫一個庫函數,目的是提高代碼的擴展性和可維護性,具體表現是:

1方便移植,比較通用。

2讀起來沒那么費勁,不用翻著手冊來讀。


自定義IO初始化函數

??在不考慮時鐘的情況下,配置一個IO口(也就是引腳)需要知道以下信息:

??1 PORT PA還是PB

??2 PIN PB1還是PB2

??3 模式 輸入還是輸出?

??我們可以把這幾個信息作為函數的參數,用一個函數來進行IO的初始化。例如初始化PB0位2Mhz的推挽輸出:


void easy_IO(GPIO_TypeDef *GPIOx,char pin,char cny,char mode)

{

    uint8_t temp;

    if(mode != shuru)

    {

        GPIOx->CRL &= ~(0xf << pin*4);

        temp =(cny<<2)|(mode);

        GPIOx ->CRL |= temp << (pin*4);

    }

}

easy_IO(GPIOB,0,tuiwan,MHZ2);//調用


??用這種方法可以比較方便地進行引腳的初始化,弊端在于,參數太多,容易出錯。有沒有更好的傳參數的方法?

使用結構體

??首先把需要的信息都放在一個結構體內。


typedef struct

{

    Uint16_t pin;

    uint8_t mode;//輸入還是輸出,速度

    uint8_t cny;//輸出模式

}GPIO_InitST;


??然后定義兩個枚舉類型,為參數可能的取值起一個好理解的名字:


typedef enum

{

    shuru = 0x00,

    MHZ10,

    MHZ2,

    MHZ50,

}ModeEm;

typedef enum

{

    tuiwan = 0x00,

    kailou,

    futuiwan,

    fukailou,

}CNYEm;


??最后定義一個函數,用于IO的初始化:


//自定義IO初始化函數

void myGPIO_Init(GPIO_TypeDef* GPIOx,GPIO_InitST* st)

{

    if(st->mode != shuru)//暫時先只處理輸出的情況

    {

        uint8_t temp;

        if(st->pin<8)//P0-P7用CRL

        {

            GPIOx->CRL &= ~(0xf<pin*4);

            temp = (st->cny<<2)|(st->mode);

            GPIOx->CRL |= temp<pin*4;

        }

        else//P8及以上是CRH

        {

            GPIOx->CRH &= ~(0xf<<(st->pin-8)*4);

            temp = (st->cny<<2)|(st->mode);

            GPIOx->CRH |= temp<<(st->pin-8)*4;              

        }

    }

}


??主函數中IO的初始化可以直接調用函數:


int main(void)

{

    GPIO_InitST myst;

    RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;

        

    myst.pin = 8;

    myst.mode = MHZ50;

    myst.cny = tuiwan;

    myGPIO_Init(GPIOB,&myst);


    myst.pin = 9;

    myGPIO_Init(GPIOB,&myst);

    while(1)

    {   

        GPIOB->ODR &= ~(1<<8);  //PB8 = 0

        GPIOB->ODR |= 1<<9;         //PB9 = 1

        delay(0xfffff);

        GPIOB->ODR &= ~(1<<9);   //PB9 = 0

        GPIOB->ODR |= 1<<8;      //PB8 = 1

        delay(0xfffff);

    }    

}


??編譯程序,下載觀察現象,跟流水燈一樣。


使用獨熱碼操作多個引腳

??有兩個不同引腳的話,需要調用兩次初始化函數,能不能調用一次初始化的函數就初始化兩個引腳?可以,代碼仍然有改進的空間。

??使用獨熱碼one-hot code, 直觀來說就是有多少個狀態就有多少比特,而且只有一個比特為1,其他全為0的一種碼制。

??如果引腳0定義為0x01,引腳1定義為0x02,引腳2定義為0x04(而不是0x03),那么0x07就可以代表這三個引腳。想同時初始化三個引腳,只需要傳入一個參數,0x07。


//自定義IO初始化函數

void myGPIO_Init(GPIO_TypeDef* GPIOx,GPIO_InitST* st)

{

    uint16_t i=0, j = 0, pflg = 0;

    uint8_t temp;

    if(st->mode != shuru)//暫時先只處理輸出的情況

    {

        for(i = 0 ; i < 16 ; i++)

        {

            j = 0x01 << i;

            pflg = st->pin & j;

            if (pflg == j)

            {

                if(i<8)//P0-P7用CRL

                {

                    GPIOx->CRL &= ~(0xf<                    temp = (st->cny<<2)|(st->mode);

                    GPIOx->CRL |= temp<                }

                else//P8及以上是CRH

                {

                    GPIOx->CRH &= ~(0xf<<(i-8)*4);

                    temp = (st->cny<<2)|(st->mode);

                    GPIOx->CRH |= temp<<(i-8)*4;                

                }

            }

        }

    }

}



??以上代碼,主要思想是通過一個for循環,將傳入的參數按位取出,并判斷這一位是0還是1。如果是1,則需要對這一位對應的IO進行操作。

??然后主函數的調用也需要做相應的修改,一次傳入PB8與PB9兩個引腳。


#define Pin_8                 ((uint16_t)0x0100)  /*!< Pin 8 selected */

#define Pin_9                 ((uint16_t)0x0200)  /*!< Pin 9 selected */

int main(void)

{

    GPIO_InitST myst;

    RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;

        

    myst.pin = Pin_8| Pin_9;

    myst.mode = MHZ50;

    myst.cny = tuiwan;

    myGPIO_Init(GPIOB,&myst);


    while(1)

    {   

        GPIOB->ODR &= ~(1<<8);  //PB8 = 0

        GPIOB->ODR |= 1<<9;         //PB9 = 1

        delay(0xfffff);

        GPIOB->ODR &= ~(1<<9);   //PB9 = 0

        GPIOB->ODR |= 1<<8;      //PB8 = 1

        delay(0xfffff);

    }    

}


改寫引腳操作

??在使用ODR寄存器的時候,總是需要關注那些不應該被操作的引腳,怕誤操作。現在由51單片機的思維改為STM32的思維。STM32提供了特別豐富,好用的寄存器,例如BSRR(端口位設置/清除)寄存器,對某個位寫1代表把對應的IO設置為高電平,其它位寫0,則不對其它位產生影響。

??看數據手冊

在這里插入圖片描述

??跟它類似的有個BRR寄存器,功能是端口位清零。

??借助這兩個寄存器,我們可以很方便的寫出IO設置為1和IO設置為0的兩個函數:


void mySetbits(GPIO_TypeDef* GPIOx,uint16_t pin)//引腳設置1

{

    GPIOx->BSRR = pin;

}

void myResetbits(GPIO_TypeDef* GPIOx, uint16_t pin)//引腳設置0

{

    GPIOx-> BRR= pin;

}


??然后修改主函數內的死循環:


while(1)

    {   

        myResetbits(GPIOB,Pin_8);  //PB8 = 0

        mySetbits(GPIOB,Pin_9);     //PB9 = 1

        delay(0xfffff);

        myResetbits(GPIOB,Pin_9);   //PB9 = 0

        mySetbits(GPIOB,Pin_8);      //PB8 = 1

        delay(0xfffff);

    }   


??最終效果還是一樣的,但代碼看上去就比較爽心悅目了。事實上,這已經很接近于庫函數的代碼了。


引入官方庫函數

??官方的固件庫提供了很多好用的函數,接下來由自定義的固件庫轉到官方標準固件庫。

??官方標準固件庫(以后簡稱官方庫)的函數可以查看文檔《STM32固件庫使用手冊的中文翻譯版.pdf》

??官方庫除了提供了詳細的函數說明,還提供了使用的例子。另外,通過函數的跳轉,可以看到官方庫的源碼,這些源碼經過千錘百煉,都是學習單片機編程的好榜樣。

??與引腳相關的函數都在GPIO章節,讀者可以自行查看。新建一個函數,IO_Init()。參考例子,稍作修改就能寫完LED引腳的初始化函數。


void IO_Init(void)

{

    GPIO_InitTypeDef GPIO_InitStructure;

     

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);   

  

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9; 

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  

    GPIO_Init(GPIOB, &GPIO_InitStructure);

}


int main(void)

{

    IO_Init();

    GPIO_SetBits(GPIOB,GPIO_Pin_8|GPIO_Pin_9);

    while(1)

    {   

        GPIO_ResetBits(GPIOB,GPIO_Pin_8);  //PB8 = 0

        GPIO_SetBits(GPIOB,GPIO_Pin_9);     //PB9 = 1

        delay(0xfffff);

        GPIO_ResetBits(GPIOB,GPIO_Pin_9);   //PB9 = 0

        GPIO_SetBits(GPIOB,GPIO_Pin_8);      //PB8 = 1

        delay(0xfffff);

    }    

}


??我們通過對寄存器的封裝,實現了最簡單的庫函數。使用STM32編程,庫函數遠比寄存器方便。所謂的庫函數,就是封裝寄存器,提供接口給用戶調用。如果是需要快速開發的時候,可以直接使用庫函數,不必糾結于是怎樣實現的,要大膽的拿來就用。但是,學習的時候,還是要考慮下庫函數的實現方式,庫函數是經過千錘百煉的優秀代碼。因此我們花費巨大的精力,自己實現了簡單的庫函數,就是為了讓大家明白,庫函數不神秘,如果需要,我們自己就能寫出來。以后使用其它的平臺,也能根據數據手冊,操作寄存器,實現功能,并把代碼封裝,優化,這才是最好的結果。

??項目式開發要避免重復造輪子,要盡快完成目標,而不是把時間浪費在不必要的細節上。庫函數與寄存器兩種開發方式并不對立,哪個方便用哪個即可。不同類型的庫也是,那個方便用哪個即可。


關鍵字:自定義  庫函數  STM32  官方標準 引用地址:從自定義的庫函數到STM32官方標準庫

上一篇:STM32掌機教程2,掌機的原理
下一篇:最后一頁

推薦閱讀

5月30日消息,據國外媒體報道, LG電子日前表示,公司計劃投資536億韓元(合4967萬美元)收購當地一家機器人制造企業Robostar股份,以加強其在下一代產業中的地位。LG電子在一份聲明中表示,該公司“計劃在7月中旬購買Robostar 20%的股份”,大約為195萬股。LG電子補充稱:“到明年年底,LG還將購買其13.4%的股份,將持股比例提高到33.4%。”行業觀察人士稱...
一次小失誤導致板子重新制作了兩次,而由于EMC測試經驗不足導致問題遲遲得不到解決。吃一塹,長一智,仿佛在電路設計的過程中就這樣不斷的用資金的投入來解決經驗上的不足。第一次:環形地線為了是電路板的地網絡和供電系統的地網絡隔離開來,在PCB設計鋪銅時畫了一個和外圍電路相接的地回路,而對內部的地采用了共模電感和差模電感來連接。 一直以為是...
協作機器人夾爪制造商OnRobot推出2.5D視覺系統Eyes,適用于各家先進機器手臂,提供外加的深度感知和零件辨識功能。 據報導,機器手臂經常遇到的難題,就是無法拾放大小、形狀或擺放方向不一的物品,通常需要外加夾具、送料盤等其它硬件協助作業,但也因此增加作業成本和復雜度,局限了設備的應用范圍。 OnRobot新推出的2.5D視覺系統Eyes,只要照一張...
近日,部分國內晶圓廠遭日本信越化學斷供光刻膠,面臨缺貨處境,加上受芯片緊缺、下游需求旺盛等影響,中芯國際、華虹宏力等本土晶圓廠積極擴產導致國內光刻膠需求量大增。 目前,多家晶圓廠正在加速驗證導入本土光刻膠。受此消息刺激,昨日,光刻膠板塊出現一輪爆發,晶瑞股份、容大感光、南大光電上海新陽等個股集體大漲。 缺不得的光刻膠:美日占據9成...

史海拾趣

問答坊 | AI 解惑

嵌入式系統咨詢

現在想搞STM32+以太網卡ENC28J60+UCOS2 還想移植UC/tcp-ip協議棧 請問大蝦們要看哪些方面的資料啊 !UC/tcp-ip協議棧在沒有剪裁的情況下占多大空間啊!…

查看全部問答∨

求助:怎么看懂電路時序圖?

電路時序圖看不懂,誰有有關電路時序圖的資料,拜謝!…

查看全部問答∨

ADI 心電信號應用筆記(完整版)

這個應用筆記是ADI中國技術支持中心的技術人員所做,個人感覺,硬件濾波設計的不錯,而且應用設計文檔制作的是中文版,使人感到通俗易懂。同時CPU采用ARM內核的ADuC7020,因此可移植性比較好,總之,推薦大家,尤其是那些對濾波技術感興趣的朋友, ...…

查看全部問答∨

可惜了啊,我的北大畢業的外甥!

許久以來,一直想說說我的外甥。      說外甥,不僅是因為我是他的舅舅,而是因為他是最讓我想不通的一個人。      認識我以及我的外甥的許多朋友,無不為我的外甥感到異常的可惜和不解。      是的,我們想不通,他究竟為什么要 ...…

查看全部問答∨

請教臺達PVD-24ES問題

1.RS232連接到電腦。。。要不要PLC接電源才能編程? 2.RS485能使rs232-485轉換器。。。(和RS485通訊卡一樣)能做控制嗎?…

查看全部問答∨

USB混合設備 USB虛擬多串口

比如我們的手機以modem方式插入電腦后,會虛擬出很多個串口。 其中包括一般的串口和modem串口。 這是怎么實現的呢,大概原理是什么。 我的理解是:一個USB設備包含多個端點(Endpoint),一般是4個,每個端點用作不同的功能,因此當插入USB主機 ...…

查看全部問答∨

blackfin 561 PROGRAMMABLE FLAGS 的問題

FIOn_FLAG_D,FIOn_FLAG_S,FIOn_FLAG_C,FIOn_FLAG_T這四個寄存器究竟有什么作用,具體的用法是怎么樣的?看了好久的硬件手冊也沒有明白。哪位仁兄能指點一下啊?…

查看全部問答∨

關于52系列T2定時器的應用,急切請教!

我的T0,T1已經用了,現在要用串口,所以模擬了一個,要用一個定時器,正好我的還有T2,我就是想設置成定時器,因為模擬串口要改定時的值,所以不用自動重裝模式,只能用捕獲了吧。我的設置如下: T2CON = 0X01;//捕獲模式 TL2 = rs_START_BIT_L ...…

查看全部問答∨

linux驅動開發的電子書籍

求linux驅動開發的電子書籍,能給鏈接是最好的,要不可以直接發到我郵箱。jamesf1982@163.com 非常感謝你的支持,對于給予幫助的朋友,每人加50分獎勵…

查看全部問答∨

皮膚

大哥,大姐們誰有做皮膚方面的經驗呀?給分享分享。謝謝…

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

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

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

 
EEWorld訂閱號

 
EEWorld服務號

 
汽車開發圈

 
機器人開發圈

電子工程世界版權所有 京ICP證060456號 京ICP備10001474號-1 電信業務審批[2006]字第258號函 京公網安備 11010802033920號 Copyright ? 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
主站蜘蛛池模板: 洪江市| 连云港市| 通道| 乐业县| 桃园县| 灵山县| 西宁市| 任丘市| 磴口县| 图片| 辛集市| 紫云| 秦皇岛市| 定襄县| 孝义市| 南郑县| 汾西县| 永靖县| 大姚县| 黄骅市| 博白县| 锡林浩特市| 武陟县| 阜南县| 晋中市| 边坝县| 凤凰县| 来安县| 临邑县| 怀仁县| 五河县| 姚安县| 汽车| 大丰市| 高密市| 河北区| 新安县| 和平区| 安乡县| 曲麻莱县| 砀山县|