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

GD32開發實戰指南(基礎篇) 第9章 呼吸燈

發布者:EtherealEssence最新更新時間:2024-11-08 來源: elecfans關鍵字:GD32  開發實戰  呼吸燈 手機看文章 掃描二維碼
隨時隨地手機看文章

開發環境:


MDK:Keil 5.30


開發板:GD32F207I-EVAL


MCU:GD32F207IK


1 呼吸燈的工作原理

呼吸燈,就是指燈光設備的亮度隨著時間由暗到亮逐漸增強,再由亮到暗逐漸衰減,很有節奏感地一起一伏,就像是在呼吸一樣,因而被廣泛應用于手機、電腦等電子設備的指示燈中。


要使用數字器件控制燈光的強弱,我們很自然就想到 PWM(脈沖寬度調制)技術。假如以LED 作為燈光設備,且由控制器輸出的 PWM 信號可以直接驅動 LED,PWM 信號中的低電平可點亮 LED 燈。當 LED 以較高的頻率進行開關(亮滅)切換時,由于視覺暫留效應,人眼是看不到 LED 燈的閃爍現象的,反映到人眼中能感覺到的是亮度的差別。即以一定的時間長度為周期,LED 燈亮的平均時間越長,亮度就越高,反之越暗。因此,我們可以使用高頻率的 PWM 信號,通過調制信號的占空比,控制 LED 燈的亮度。


那么具體我們應該控制 LED 燈以怎樣的亮度曲線變化能夠達到最好的效果呢?亮度隨著時間逐漸變強再衰減,可以用兩種常見的數學函數表示,分別是半個周期的正弦函數與指數上升曲線及其對稱得到的下降曲線。

1683894862773yoqqladc47

相對來說,使用下凹函數曲線燈光處于暗的狀態更長,所以指數函數的曲線更符合我們呼吸燈的亮度變化要求。


2 呼吸燈實現

2.1 簡單方式

筆者先用最簡單的方式來實現,也就是定時改變比較寄存器的值。


1.初始化 GPIO


下面分析具體的定時器配置代碼。本實驗使用 PB0 作為定時器 PWM 輸出通道,先對它進行初始化。作 PWM 輸出通道的引腳需要被配置為復用推挽輸出模式。


/*

    brief      configure PWM GPIO

    param[in]  none

    param[out] none

    retval     none

*/

static void timer_gpio_init(void)

{

    rcu_periph_clock_enable(RCU_GPIOB);

    rcu_periph_clock_enable(RCU_AF);


    /* Configure PB0 (TIMER2 CH2) as alternate function */

    gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_0);

}

2.配置定時器模式


在timer2_init()函數中,完成了呼吸燈所需要的定時器 PWM 輸出模式配置。


/*

    brief      configure the Breath LED peripheral

    param[in]  none

    param[out] none

    retval     none

  */

void breath_led_init(void)

{

    /* TIMER2 configuration: generate PWM signals with different duty cycles:

       TIMER2CLK = SystemCoreClock / 120 = 1MHz */

    timer_oc_parameter_struct timer_ocintpara;

    timer_parameter_struct timer_initpara;


    /* configure the GPIO ports */

    timer_gpio_init();


    rcu_periph_clock_enable(RCU_TIMER2);


    timer_deinit(TIMER2);


    /* TIMER1 configuration */

    timer_initpara.prescaler         = 119;

    timer_initpara.alignedmode       = TIMER_COUNTER_EDGE;

    timer_initpara.counterdirection  = TIMER_COUNTER_UP;

    timer_initpara.period            = 250;

    timer_initpara.clockdivision     = TIMER_CKDIV_DIV1;

    timer_initpara.repetitioncounter = 0;

    timer_init(TIMER2, &timer_initpara);


    /* CH0 configuration in PWM mode 0 */

    timer_ocintpara.outputstate  = TIMER_CCX_ENABLE;

    timer_ocintpara.outputnstate = TIMER_CCXN_DISABLE;

    timer_ocintpara.ocpolarity   = TIMER_OC_POLARITY_HIGH;

    timer_ocintpara.ocnpolarity  = TIMER_OCN_POLARITY_HIGH;

    timer_ocintpara.ocidlestate  = TIMER_OC_IDLE_STATE_LOW;

    timer_ocintpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;


    timer_channel_output_config(TIMER2, TIMER_CH_2, &timer_ocintpara);


    /* CH0 configuration in PWM mode 0,duty cycle 25% */

    timer_channel_output_pulse_value_config(TIMER2, TIMER_CH_2, 0);

    timer_channel_output_mode_config(TIMER2, TIMER_CH_2, TIMER_OC_MODE_PWM0);

    timer_channel_output_shadow_config(TIMER2, TIMER_CH_2, TIMER_OC_SHADOW_DISABLE);


    /* auto-reload preload enable */

    timer_auto_reload_shadow_enable(TIMER2);

    /* TIMER2 enable */

    timer_enable(TIMER2);

}

這個定時器的模式配置主要分為三個部分,分別為時基初始化,輸出模式初始化。


時基初始化

代碼中前面的部分是定時器的時基初始化,這部分主要負責配置定時器的定時周期、時鐘頻率、計數方式等。它使用到庫函數timer_init()函數,利用結構體timer_parameter_struct進行配置,該結構體有以下成員:


period

定時周期,實質是存儲到重載寄存器CAR的數值,脈沖計數器從 0 累加到這個值上溢或從這個值自減至 0 下溢。這個數值加 1 然后乘以時鐘源周期就是實際定時周期。


本實驗中向該成員賦值為 255,即定時周期為(255+1)* T ,T 為定時器的時鐘周期。


prescaler

對定時器時鐘CLK 的預分頻值,分頻后作為脈沖計數器TIMERx_CNT的驅動時鐘,得到脈沖計數器的時鐘頻率為:CNT=CLK/(N+1),其中 N 為即為賦給本成員的時鐘分頻值。


本實驗給 prescaler 成員賦值為 119,即對時鐘 120 分頻,所以定時器的時鐘周期 T 為 120/120000000。


clockdivision

時鐘分頻因子。怎么又出現一個配置時鐘分頻的呢?要注意這個clockdivision和上面的 prescaler 是不一樣的。prescaler 預分頻配置是對CLK進行分頻,分頻后的時鐘被輸出到脈沖計數器CNT。


本實驗中是使用內部時鐘CLK 作為定時器時鐘源的,沒有進行濾波所以配置clockdivision為任何數值都沒有影響。


alignedmode

本成員配置的為脈沖計數器 CNT 的計數模式,分別為向上計數,向下計數,及中央對齊模式。向上計數即 CNT 從 0 向上累加到 period 中的值,(重載寄存器 CAR 的值),產生上溢事件;向下計數則 CNT 從period 的值累減至0,產生下溢事件。而中央對齊模式則為向上、向下計數的合體,CNT 從 0 累加到period 的值減 1 時,產生一個上溢事件,然后向下計數到 1 時,產生一個計數器下溢事件,再從 0 開始重新計數。


輸出模式配置

在本函數代碼的后面是關于定時器的輸出模式配置的。通用定時器的輸出模式由 timer_oc_parameter_struct類型結構體的主要有以下幾個成員:


outputstate

配置輸出模式的狀態使能或關閉輸出。


outputnstate

本成員的參數值即為比較寄存器 CH2CV的數值,當脈沖計數器CNT與CH2CV的比較結果發生變化時,輸出脈沖將發生跳變。


ocpolarity

有效電平的極性,把 PWM 模式中的有效電平設置為高電平或低電平。


本實驗中向該成員賦值為 TIMER_OC_POLARITY_LOW (有效電平為低電平),因為在上面把輸出模式配置為 PWM0 模式,向上計數,所以在 CNT< CH0CV 時,通道 n 輸出為低電平,否則為高電平。


ocnpolarity

用于比較有效電平的極性。


本實驗中就是通過不斷改變比較寄存器CH2CV的值,達到控制 PWM 信號的占空比呈指數曲線變化的目的。在本函數代碼中,我們對該成員賦予初始為 0,而改變比較寄存器 CH0CV 值的操作是在中斷服務函數中修改的。填充完輸出模式初始化結構體后,調用輸出模式初始化函數 timer_channel_output_config()對通道進行初始化。


以上是最基本的PWM輸出調制實現呼吸燈。


筆者接下來還要講解一下重映射的輸出配置。在這里講解的是通過重映射 TIMER2_CH2到 PB0 上,由 TIMER2_CH2 輸出 PWM 來控制LED的亮度。下面我們介紹通過庫函數來配置該功能的步驟。


1)開啟 TIMER2時鐘以及復用功能時鐘,配置 PB0為復用輸出。


要使用 TIMER2,我們必須先開啟 TIMER2的時鐘,這點相信大家看了這么多代碼,應該明白了。這里我們還要配置 PB0為復用輸出,此時,PB0屬于復用功能輸出。在此只列出庫函數設置 AFIO 時鐘的方法。


rcu_periph_clock_enable(RCU_AF);

其余的和前面的配置一樣,就不再列出了。


2)初始化 TIMER2,設置 TIMER2的 CAR 和 PSC。


3)設置 TIMER2_CH2 的 PWM 模式,使能 TIMER2的 CH2 輸出。


4)使能 TIMER2。


在完成以上設置了之后,我們需要使能 TIMER2。 使能 TIMER2的方法前面已經講解過:


timer_enable(TIMER2);

5)修改 TIMER2_ CH2CV來控制占空比。


最后,在經過以上設置之后, PWM 其實已經開始輸出了,只是其占空比和頻率都是固定的,而我們通過修改 TIMER2_CH2CV則可以控制 CH2 的輸出占空比。繼而控制LED的亮度。在庫函數中,修改 TIMER2_CH2CV占空比的函數是:


void timer_channel_output_pulse_value_config(uint32_t timer_periph, uint16_t channel, uint32_t pulse)

通過以上5個步驟,我們就可以控制 TIMER2的 CH2 輸出 PWM 波了。


接下來看看主函數的代碼:


/*

    brief      main function

    param[in]  none

    param[out] none

    retval     none

*/

int main(void)

{

    uint16_t i = 0;

    FlagStatus breathe_flag = SET;


    //systick init

    sysTick_init();


    /* configure the Breath LED peripheral */

    breath_led_init();


    while(1)

    {

        /* delay a time in milliseconds */

        delay_ms(5);

        if(SET == breathe_flag) 

        {

            i++;

        }

        else

        {

            i--;

        }

        if(250 < i)

        {

            breathe_flag = RESET;

        }

        if(0 >= i)

        {

            breathe_flag = SET;

        }

        /* configure TIMER channel output pulse value */

        //timer_channel_output_pulse_value_config(TIMER2, TIMER_CH_2, i);

        TIMER_CH2CV(TIMER2) = (uint32_t)i;

    }

}

代碼很簡單,就是不斷改變CH2CV的值從而控制 CH2 的輸出占空比。


2.2 中斷方式

1.生成指數曲線 PWM 數據


要實現 LED 亮度隨著指數曲線變化,我們需要使用占空比呈指數曲線變化的 PWM 信號,而這樣的信號由定時器經過查表產生。這個表的數據存儲在程序中的數組 indexWave中。


uint8_t indexWave[] = {1,1,2,2,3,4,6,8,10,14,19,25,33,44,59,80,

107,143,191,255,255,191,143,107,80,59,44,33,25,19,14,10,8,6,4,3,2,2,1,1};

這個表有 40 個數字,從圖中可以看到這些數字呈指數上升再衰減,正好是呼吸燈的一個控制周期。數字的大小范圍是 0255,即把 LED 的亮度分為了 0255 個等級。


假如我們把定時器的脈沖計數器 CNT 上限設置為 255,把這個表的數據一個一個地賦值到定時器的比較寄存器CH2CV中,那么在每個 PWM 周期中,當 CNT的計數值小于比較寄存器 CH2CV的值時, 就會在通道中輸出低電平,點亮 LED,而隨著 CCR 的值由 LED 亮度表得來,所以 LED 點亮的時間就會呈圖中的曲線變化,實現呼吸燈的功能。


這個表的數據是使用 matlab 軟件生成的。該代碼運行后會生成一個“index_wave.c”的文件,用戶把該文件中的數據復制到工程中的數組中即可。


%本代碼用于產生呼吸燈使用的指數函數數據

clear;


x = [0 : 8/19 : 8];       %設置序列 ,指數上升

up = 2.^x ;               %求上升指數序列  

up = uint8(up);           %化為8位數據


y = [8: -8/19 :0];       %設置序列 ,指數下降

down = 2.^y ;            %求下降指數序列

down = uint8(down);      %化為8位數據


line = [[0:8/19:8],[8:8/19:16]]         %拼接序列

val = [up , down]                       %拼接輸出序列


dlmwrite('index_wave.c',val);       %輸出到文件index_wave.c

plot(line,val,'.');                 %顯示波形圖

2.初始化 GPIO


這部分和前面的一樣,沒啥好說的。


3.配置定時器模式


這里也差不多,只是將分頻系數設置的稍微大些,另外開啟了中斷。


/*

    brief      configure the Breath LED peripheral

    param[in]  none

    param[out] none

    retval     none

  */

void breath_led_init(void)

{

    /* TIMER2 configuration: generate PWM signals with different duty cycles*/

    timer_oc_parameter_struct timer_ocintpara;

    timer_parameter_struct timer_initpara;


    /* configure the GPIO ports */

    timer_gpio_init();


    rcu_periph_clock_enable(RCU_TIMER2);


    timer_deinit(TIMER2);


    /* TIMER2 configuration */

    timer_initpara.prescaler         = 3999;

    timer_initpara.alignedmode       = TIMER_COUNTER_EDGE;

    timer_initpara.counterdirection  = TIMER_COUNTER_UP;

    timer_initpara.period            = 255;

    timer_initpara.clockdivision     = TIMER_CKDIV_DIV1;

    timer_initpara.repetitioncounter = 0;

    timer_init(TIMER2, &timer_initpara);


    /* CH2 configuration in PWM mode 0 */

    timer_ocintpara.outputstate  = TIMER_CCX_ENABLE;

    timer_ocintpara.outputnstate = TIMER_CCXN_DISABLE;

    timer_ocintpara.ocpolarity   = TIMER_OC_POLARITY_HIGH;

    timer_ocintpara.ocnpolarity  = TIMER_OCN_POLARITY_HIGH;

    timer_ocintpara.ocidlestate  = TIMER_OC_IDLE_STATE_LOW;

    timer_ocintpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;

[1] [2]
關鍵字:GD32  開發實戰  呼吸燈 引用地址:GD32開發實戰指南(基礎篇) 第9章 呼吸燈

上一篇:GD32 MCU如何使用雙ADC內核提高ADC采樣率?
下一篇:GD32開發實戰指南(基礎篇) 第10章 串口通信

推薦閱讀最新更新時間:2025-04-16 11:18

GD32開發實戰指南(基礎篇) 第19章 程序加密
開發環境: MDK:Keil 5.30 開發板:GD32F207I-EVAL MCU:GD32F207IK 1 程序加密工作原理 GD32通過讀取芯片唯一ID號來實現程序的保護,防止被抄襲。96位的產品唯一身份標識所提供的參考號碼對任意一個GD32微控制器,在任何情況下都是唯一的。用戶在何種情況下,都不能修改這個身份標識。按照用戶不同的用法,可以以字節(8位)為單位讀取,也可以以半字(16位)或者全字(32位)讀取。在這里要提醒讀者, 要注意大端小端模式 。 2 程序加密具體代碼實現 其實讀取ID很簡單,如果存儲ID的變量為8位。則需要讀取12次,如下所示。 uint8_t Sys_ID ,i; for(i=0;i 12
[單片機]
初學stm32-PWM的應用-呼吸燈
PWM概述 脈沖寬度調制(PWM),是英文“Pulse Width Modulation”的縮寫,簡稱脈寬調制,是利用微處理器的數字輸出來對模擬電路進行控制的一種非常有效的技術。簡單一點,就是對脈沖寬度的控制,PWM 原理如圖: STM32F4 的定時器除了 TIM6 和 7。其他的定時器都可以用來產生 PWM 輸出。通過查看開發板的原理圖(如下),可發現PF9引腳連接LED0,同時也是作為TIM14_CH1的復用輸出端口,知道此前提,我們就可以開始搞事情了。 PWM輸出步驟 使能定時器14和相關IO口時鐘。 使能定時器14時鐘:RCC_APB1PeriphClockCmd(); 使能GPIOF時鐘:RCC_AHB1Per
[單片機]
初學stm32-PWM的應用-<font color='red'>呼吸燈</font>
調試模式下如何調試看門狗?
大家在調試GD32 MCU系統的時候,若開了看門狗外設,是否會碰到進入調試模式看門狗就會咬狗造成無法調試的問題? 碰到這種情況,一般是將看門狗關閉,然后再進行調試,但這個時候看門狗外設就無法工作了,GD32 MCU的調試模塊可支持調試模式下看門狗的工作,包括斷點還有單步的時候暫停看門狗計數,進而不會造成調試模式下看門狗咬狗復位的現象。 寄存器上可以控制以下兩個控制位,比如希望調試FWDGT獨立看門狗,就可以將FWDGT_HOLD控制位置1,就可以在調試模式下,當內核停止時保持FWDGT計數器的時鐘。 軟件上相關配置可參考以下代碼: dbg_periph_enable(DBG_FWDGT_HOLD);//打開獨立看門狗
[單片機]
調試模式下如何調試看門狗?
小廣播
設計資源 培訓 開發板 精華推薦

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

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

 
EEWorld訂閱號

 
EEWorld服務號

 
汽車開發圈

 
機器人開發圈

電子工程世界版權所有 京ICP證060456號 京ICP備10001474號-1 電信業務審批[2006]字第258號函 京公網安備 11010802033920號 Copyright ? 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
主站蜘蛛池模板: 碌曲县| 抚州市| 浦城县| 内江市| 荣成市| 遵化市| 乌拉特后旗| 越西县| 红桥区| 舒城县| 新郑市| 大足县| 望奎县| 子长县| 滕州市| 贵定县| 梁山县| 尉氏县| 昌乐县| 虎林市| 沛县| 定结县| 岳阳市| 万荣县| 屏东市| 锡林浩特市| 舟山市| 荣成市| 平顺县| 海城市| 娱乐| 商南县| 黄龙县| 西峡县| 安泽县| 凌海市| 秭归县| 北川| 沁源县| 河西区| 运城市|