如何将 10 位模拟信号缩放为 8 位 PWM?

问题描述 投票:0回答:1

我正在使用 PIC18F47-Q18 Curiosity HPC 开发板和 MPLAB X IDE v6.20。

目标是将模拟输出的 10 位值存储到 8 位 PWM 中。取决于模拟对齐的合理性。 ADRESL 保存数据的前 8 位(2^0 到 2^8),ADRESH 保存位 0 和位 1 中的最后两位(2^9 和 2^10)。通过做

PWM4DCH = ADRESL;
。当我转动电位器时,LED 会变亮。然而,在某个点之后,PWM 周期会重新启动,并且 LED 在再次变亮之前会关闭。如此重复 4 次。我相信这是因为我使用的微控制器是 Fosc/4。最终目标是顺时针旋转电位器时使LED达到最大亮度。

我粘贴了下面的代码,并提供了尽可能多的细节和信息。此外,我目前使用轮询,但当我了解它们如何工作时,我将使用中断标志重新创建它。

// CONFIG1L
#pragma config FEXTOSC = OFF
#pragma config RSTOSC = HFINTOSC_64MHZ

// CONFIG1H
#pragma config CLKOUTEN = OFF
#pragma config CSWEN = OFF
#pragma config FCMEN = OFF

// CONFIG3L
#pragma config WDTCPS = WDTCPS_31
#pragma config WDTE = OFF

#define clock OSCCON1           // define the timer control bits
#define freq OSCFRQ

#define enable_timer T2CONbits.T2ON         // define the timer control bits
#define interrupt_enable PIE4bits.TMR2IE 
#define PB1 PORTBbits.RB4
#define PB2 PORTCbits.RC5
#define light PORTAbits.RA7

void main(void) {   
    clock = 0x60;               // use High Mhz clock
    freq = 0x03;                // Use 8Mhz clock
    
    T2CLKCON = 0x01;            // Make Timer2 Fosc/4
    
    ANSELA = 0x01;              // set up port A,B,C D/A
    TRISA = 0x01;               // set up port A,B,C I/O
    ANSELB = 0x00;   
    TRISB = 0xFF;   
    ANSELC = 0x00;   
    TRISC = 0xFF;   
  
    T2PR = 0xC7;                // period of the PWM
    PWM4DCH = 0x95;             // set up duty cycle of PWM
    PWM4DCL = 0x10;             // set up duty cycle of PWM
    RA4PPS = 0x08;              // set RA4 to  be PWM output            
    T2CON = 0x20;               // set pre scale value of 1:4
    PWM4CONbits.PWM4EN = 1;     // enable the PWM
    PWM4CONbits.POL = 1;        // reverse Polarity of PWM

    while (1)
    {
        enable_timer=1;                 // enable the timer 2
        while(PIR4bits.TMR2IF==0);      // Monitor that the interrupt flag is zero
        enable_timer=0;                 // disable the timer
        PIR4bits.TMR2IF=0;              // clear the interrupt flag
       
        ADCON0 = 0x84;                  // ADC is enabled and ADFM is right justified
        ADPCH = 0x00;                   // Selected channel is RA0       
        ADCON0bits.GO =1;               // start ADC conversion
        while (ADCON0bits.GO ==0);      // using polling method to wait until GO bit is 0      
        PWM4DCH = ADRESL;               // display ADRESL results on PWM4DCH
        ADCON0bits.ADON = 0;            // Turn off ADC enable bit
    }
    return;
}

我尝试将 ADRESL 和 ADRESH 设置为整数 x 和 y,然后再将它们相加并输出到 PWM:

int x;
int y;
int z;

x = ADRESL;
y = ADRESH << 8;
z = (ADRESH << 8 | ADRESL);

PWM4DCH = z;

使用电位器时LED不会做任何事情。

我尝试做上面同样的事情,但是直接进入PWM4DCH:

PWM4DCH = (ADRESH<<8 | ADRESL);

与上面相同的问题。

c scaling bit-shift pic18
1个回答
0
投票

要将 10 位 ADC 值缩放为 8 位 PWM:

  1. 右对齐 ADC 结果。
  2. 通过丢弃最低有效 2 位来提取最高有效 8 位。

使用公式:

PWM4DCH = (ADRESH << 6) | (ADRESL >> 2);

说明:

  • ADRESH << 6
    :将
    ADRESH
    的 2 个 MSB 与 8 位值的前 2 位对齐。
  • ADRESL >> 2
    :保留
    ADRESL
    的高6位,同时丢弃低2位。
  • |
    组合形成 8 位缩放结果。

您提到的警告是由于从较大的整数类型隐式转换为 8 位无符号类型所致。显式强制转换以避免这种情况:

PWM4DCH = (unsigned char)((ADRESH << 6) | (ADRESL >> 2));
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.