簡體   English   中英

寄存器層的STM32F4-PWM控制

[英]STM32F4-PWM control in register layer

我正在通過 ADC 值更改 LED 亮度。實際上我使用標准 periph 庫,它工作得很好但是當我想在寄存器層中編寫我的代碼時。我找不到除了 ST 食譜文檔之外的任何文檔。所以我寫了我的代碼食譜引用。它可以工作,但不是我想要的,我可以一次改變 LED 的亮度。我能做些什么來連續改變 LED 的值? 我的代碼如下所示

while (1)
  {     
    value=ADC_Read();
    //PD12,PD13,PD14,PD15 selected for pwm control
     pulse_value=map(value,0,4095,0,9999);
    
     TIM4->CCR1|=pulse_value;
     TIM4->CCR2|=pulse_value;
  
     TIM4->CCMR1|=0;
     TIM4->CCMR1|=0x60;
     TIM4->CCMR1|=0x6000;
     
      TIM4->CCER|= 1<<0 | 1<<4;
      
      
      delay(1680000);
  
     TIM4->CCR3|=pulse_value;
     TIM4->CCR4|=pulse_value;
  
     TIM4->CCMR2|=0;
     TIM4->CCMR2|=0x60;
     TIM4->CCMR2|=0x6000;
     
      TIM4->CCER|= 1<<8 | 1<<12;
      TIM4->CR1|=0x1;
      
      delay(1680000);
   TIM4->CCER|= 1<<0 | 0<<4| 0<<8 | 0<<12;

因此,當我在三個 LED 上弄亂了 PWM 時,我認為這是在 STM32 芯片上(STM32F4 未來太模糊了,需要更多的零件號)(這是一個 STM32F031F4P6),看起來定時器類似並不少見跨產品重復使用 IP。

PUT32(TIM2_CR1,0x00000000);
PUT32(TIM2_CCR2,200-1);
PUT32(TIM2_CCR3,400-1);
PUT32(TIM2_CCR4,600-1);
PUT32(TIM2_ARR, 800-1);
PUT32(TIM2_CNT,0x00000000);
PUT32(TIM2_PSC,0x00000000);
PUT32(TIM2_CCMR1,(6<<12));
PUT32(TIM2_CCMR2,(6<<12)|(7<<4));
PUT32(TIM2_CCER,(1<<4)|(1<<8)|(1<<12));
PUT32(TIM2_CR1,0x00000001);

while(1)
{
    for(ra=0;ra<800;ra++)
    {
        PUT32(TIM2_CCR2,ra);
        PUT32(TIM2_CCR3,ra);
        PUT32(TIM2_CCR4,ra);
        for(rb=0;rb<2000;rb++) dummy(rb);
    }
    for(ra--;ra;ra--)
    {
        PUT32(TIM2_CCR2,ra);
        PUT32(TIM2_CCR3,ra);
        PUT32(TIM2_CCR4,ra);
        for(rb=0;rb<2000;rb++) dummy(rb);
    }
}

這可以作為參考(是的,從技術上講,其中一些是 16 位寄存器,但 st 在允許 32 位訪問方面很靈活,請注意它們無論如何都將寄存器隔開在字邊界上。

所以這是一個問題

 TIM4->CCR1|=pulse_value;
 TIM4->CCR2|=pulse_value;

你想用那里的東西替換那些不 ORR 它們的位,最終它們將全部是

TIM4->CCR1 = (TIM4->CCR1)&(~0xFFFF)|pulse_value;

但實際上由於寄存器沒有分區,它是一個字段/值

TIM4->CCR1 = pulse_value;

將是正確的做法。

這當然什么都不做:

TIM4->CCMR1|=0;

你的意思

TIM4->CCMR1=0;

? 為什么要單獨設置字段(作為一種習慣,並且每次讀取-修改-寫入都會更改外圍設備,只需一次性設置您想要的寄存器位,無論是一次讀取-修改-寫入還是一次寫入)。 作為一般規則,對外圍設備執行這樣的單獨操作中的字段是不安全的。 而且你不能只是或等於一個寄存器而不用與字段來清除它。

Bits 6:4 OC1M: Output compare 1 mode
110: PWM mode 1

TIM4->CCMR1|=0x60;

相反,那個領域需要這樣的東西

TIM4->CCMR1 = (TIM4->CCMR1&(~(7<<4))) | (6<<4);

我覺得它更具可讀性

x = TIM4->CCMR1;
x&=(~7)<<4;
x|=   6<<4;
TIM4->CCMR1 = x;

甚至更好

Bits 14:12 OC2M[2:0]: Output compare 2 mode
Bits 6:4 OC1M: Output compare 1 mode

x = TIM4->CCMR1;
x&=(~7)<<12;
x|=   6<<12;
x&=(~7)<<4;
x|=   6<<4;
TIM4->CCMR1 = x;

我懷疑你真正想做的是:

 TIM4->CCMR1=0;
 TIM4->CCMR1|=0x6060;

寄存器重置為 0x0000 所以

 TIM4->CCMR1=0x6060;

會很好的。 或者為了可讀性

 TIM4->CCMR1=(6<<12)|(6<<4);

您可以直接從代碼中的參考手冊中看到 12 和 4 以及 6(110 二進制)。

而且我相信(你可以像我一樣閱讀文檔)你只需要設置一次 pwm 以便所有寄存器只在 init 時執行一次,然后對於你從 adc 讀取的每個新值,您只需更改比較寄存器的值。 並且在那個時期或下一個時期,pwm 將改變 state 相對於新的寄存器值(取決於你何時相對於當前時期編寫它)。

你非常接近我想你明白了,只需練習你的 AND、OR、XOR 和 NOT 技能(按位邏輯運算)。

在處理一個 gpio 寄存器時,其中引腳 A3 可能是小部件 B 的一些控制信號,而 A5 可能是小部件 X 的一些控制信號,並且您希望為每個小部件(一些外圍設備或 LED 或按鈕或其他)擁有單獨的軟件,然后讀取-修改-寫入(正確完成)根據該芯片的該 gpio 外設的邏輯如何工作而產生很大的意義。 但是,如果您正在配置一個 uart、一個定時器、一個 spi controller 等。如果您需要一次性控制寄存器中的所有位,您只需一個驅動程序即可擁有全部功能,然后讀取-修改-寫入就不需要了一定是有道理的。 就寄存器訪問而言,只需將整個寄存器寫入該配置所需的所有位即可。 為了代碼的可讀性(相對術語,美麗在旁觀者的眼中,對於每個他(/她)自己的,等等),您可以選擇只寫整個事物的十六進制值,做一些轉換,以便您可以輕松將值轉換為參考手冊/從參考手冊轉換,以幫助減少錯誤。 制作一些對變量進行位操作的宏,以便您可以真正將參考手冊中的值插入代碼中 (SET_BITS(x,16,14,6); SET_BITS(x,6,4,6) ;) ETC。

你的主循環可能最終看起來像

while (1)
{     
  value=ADC_Read();
  //PD12,PD13,PD14,PD15 selected for pwm control
   pulse_value=map(value,0,4095,0,9999);

   TIM4->CCR1=pulse_value;
   TIM4->CCR2=pulse_value;
   TIM4->CCR3=pulse_value;
   TIM4->CCR4=pulse_value;
   delay(1680000);
}

前面的設置是 TIM 中需要寫入以使其工作的寄存器的 rest。 可能對 CCR1 寄存器或某種起點使用一個小值,或者進行 adc 讀取,然后使用該 adc 讀取 pulse_value 進行設置,然后將 go 放入 while 循環。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM