assembly - 如何在AVR中产生占空比为20%的PWM脉冲?

标签 assembly avr pwm

我想在ATMEGA8中timer0的PWM模式下产生一个PWM波,如下图:

enter image description here

它具有 20% 的占空比,但不能单独使用 PWM 模式来实现。 我尝试在反向模式下使用快速 PWM 模式,并尝试检查 TCNT0 直到它达到 64H,这样我就可以在达到 64H 时清除 OC0 PIN。

我想知道当我手动清除 OC0 时此方法是否正常工作?

这是我的代码:

.DEF A = R16             ;GENERAL PURPOSE ACCUMULATOR

.ORG $0000

ON_RESET:
    SBI DDRB,3           ;SET PORTB3(OC0) FOR OUTPUT
    LDI A,0b01011011    ;SET TO FAST PWM MODE
    OUT TCCR0,A    ;SET PRESCALER/DIVIDER TO /32    
    LDI A,32             ;DIFFERENT VALUE
    OUT OCR0,A          ;FOR COMPARE


MAIN_LOOP:
PLOOP: IN   A,TCNT0        ;COMPARE TCNT0
       ANDI A,0x64H   ;COMPARE TCNT0 TO 64 TO MAKE IT ZERO
       BRNEQ PLOOP
       CBI  PINB,3     
RJMP MAIN_LOOP;A CHECK FOR TIMER LOOP

最佳答案

AVR 中的 PWM 周期通常以定时器溢出开始(相位校正和相位/频率校正 PWM 除外)...换句话说,您可以控制占空比,但不能控制启动。在您的示例中 - 无论出于何种原因 - 您想要控制 PWM 周期的开始(定时器溢出后 32 小时)以及占空比(大约 FFh 的 20% ... 32 小时)。

所以你可能需要考虑

  • 使用自由运行的定时器每 1/FFh 生成一次中断
  • 使用一个 8 位寄存器,在每次调用中断期间递增该寄存器(它会在 FF 之后溢出……没关系)
  • 如果该寄存器读取 32h 或 64h,则反转输出引脚(或如下设置/重置)
  • 在 SEI 之前将输出引脚设置为 0 来初始化您的程序

我很快就劫持了我的 AT90USBKEY2 上的一个 PWM LED 设备 - 使用 AT90USB1287 处理器 - 并根据它进行了修改。到上面(抱歉,代码有点长:-o ...见下文)

编辑:

严格来说,这一切只有在您有同步点时才有意义……如果您单独查看 20% 波形,您无法确定它是否从时隙 0x00 开始。或0x32 ...示波器始终在脉冲的上升(或下降)沿同步。因此,您需要通过在 PWM_SUBLEVEL 溢出时在不同引脚上输出脉冲来提供 PWM 帧开始的引用。 。使用来自另一个引脚的脉冲作为示波器的同步源,当您开始更改PWM_ON时,您开始看到相位的移动。 .

/*
 * AsmFile1.asm
 *
 *  Created: 19.05.2015 22:01:49
 *   Author: MikeD
 */ 
.nolist
.include <usb1287def.inc>
.list

.def TMP1 = R16
.def TMP2 = R17
.def PWM_SUBLEVEL = R18
.def PWM_ON = R19
.def PWM_OFF = R20

.cseg
.org 0x0000
    jmp V_RESET ;            1 $0000 RESET               External pin, Power-on reset, Brown-out reset, Watchdog reset, and JTAG AVR reset
    jmp V_NOINT ;            2 $0002 INT0                External Interrupt Request 0
    jmp V_NOINT ;            3 $0004 INT1                External Interrupt Request 1
    jmp V_NOINT ;            4 $0006 INT2                External Interrupt Request 2
    jmp V_NOINT ;            5 $0008 INT3                External Interrupt Request 3
    jmp V_NOINT ;            6 $000A INT4                External Interrupt Request 4
    jmp V_NOINT ;            7 $000C INT5                External Interrupt Request 5
    jmp V_NOINT ;            8 $000E INT6                External Interrupt Request 6
    jmp V_NOINT ;            9 $0010 INT7                External Interrupt Request 7
    jmp V_NOINT ;           10 $0012 PCINT0              Pin Change Interrupt Request 0
    jmp V_NOINT ;           11 $0014 USB General         USB General Interrupt request
    jmp V_NOINT ;           12 $0016 USB Endpoint/Pipe   USB ENdpoint/Pipe Interrupt request
    jmp V_NOINT ;           13 $0018 WDT                 Watchdog Time-out Interrupt
    jmp V_NOINT ;           14 $001A TIMER2 COMPA        Timer/Counter2 Compare Match A
    jmp V_NOINT ;           15 $001C TIMER2 COMPB        Timer/Counter2 Compare Match B

    jmp V_T2OVF ;           16 $001E TIMER2 OVF          Timer/Counter2 Overflow

    jmp V_NOINT ;           17 $0020 TIMER1 CAPT         Timer/Counter1 Capture Event
    jmp V_NOINT ;           18 $0022 TIMER1 COMPA        Timer/Counter1 Compare Match A
    jmp V_NOINT ;           19 $0024 TIMER1 COMPB        Timer/Counter1 Compare Match B
    jmp V_NOINT ;           20 $0026 TIMER1 COMPC        Timer/Counter1 Compare Match C
    jmp V_NOINT ;           21 $0028 TIMER1 OVF          Timer/Counter1 Overflow
    jmp V_NOINT ;           22 $002A TIMER0 COMPA        Timer/Counter0 Compare Match A
    jmp V_NOINT ;           23 $002C TIMER0 COMPB        Timer/Counter0 Compare match B
    jmp V_NOINT ;           24 $002E TIMER0 OVF          Timer/Counter0 Overflow
    jmp V_NOINT ;           25 $0030 SPI, STC            SPI Serial Transfer Complete
    jmp V_NOINT ;           26 $0032 USART1 RX           USART1 Rx Complete
    jmp V_NOINT ;           27 $0034 USART1 UDRE         USART1 Data Register Empty
    jmp V_NOINT ;           28 $0036 USART1TX            USART1 Tx Complete
    jmp V_NOINT ;           29 $0038 ANALOG COMP         Analog Comparator
    jmp V_NOINT ;           30 $003A ADC                 ADC Conversion Complete
    jmp V_NOINT ;           31 $003C EE READY            EEPROM Ready
    jmp V_NOINT ;           32 $003E TIMER3 CAPT         Timer/Counter3 Capture Event
    jmp V_NOINT ;           33 $0040 TIMER3 COMPA        Timer/Counter3 Compare Match A
    jmp V_NOINT ;           34 $0042 TIMER3 COMPB        Timer/Counter3 Compare Match B
    jmp V_NOINT ;           35 $0044 TIMER3 COMPC        Timer/Counter3 Compare Match C
    jmp V_NOINT ;           36 $0046 TIMER3 OVF          Timer/Counter3 Overflow
    jmp V_NOINT ;           37 $0048 TWI                 2-wire Serial Interface
    jmp V_NOINT ;           38 $004A SPM READY           Store Program Memory Ready

V_RESET:
; prepare stack ... special write procedure
    ldi TMP1, low(ramend)
    ldi TMP2, high(ramend)
    out spl, TMP1
    out sph, TMP2

; increase CLKIO from 1 to 8MHz ... special write procedure
    ldi TMP1, 0b1000_0000
    ldi TMP2, 0b0000_0000
    sts CLKPR, TMP1
    sts CLKPR, TMP2

; initialize variables
    clr PWM_SUBLEVEL 
    ldi PWM_ON, 0x32
    ldi PWM_OFF, 0x64

; prepare LED ports
; D2-RD on PORTD4 
; D2-GN on PORTD5 
; D5-RD on PORTD7 
; D5-GN on PORTD6 
    ldi TMP1, 0b1111_0000
    out DDRD, TMP1

; Timer2 (8bit) without prescaler in normal mode
; generates interrupt every 256 CPU clock cycles (32 us) for PWM sublevel
; we use this for PWM as Timer2 has the highest priority amongst timers

    clr TMP1
    sts TCCR2A, TMP1                ; normal mode, port pins disabled

    ldi TMP1, (1 << CS20)
    sts TCCR2B, TMP1                ; internal clock, no prescaler

    ldi TMP1, (1 << TOIE2) 
    sts TIMSK2, TMP1                ; overflow interrupt enable

    sei                             ; set general interupt enable flag

MAIN:
    rjmp MAIN

V_T2OVF:
; fires every 32 us

    inc PWM_SUBLEVEL                  ; overflows every 8.192 ms, f=122.07... Hz
    cp  PWM_SUBLEVEL, PWM_ON
    breq GO_HI
    cp  PWM_SUBLEVEL, PWM_OFF
    breq GO_LO
    reti
GO_HI:
    sbi PORTD, PORTD4
    reti
GO_LO:
    cbi PORTD, PORTD4
    reti

V_NOINT:
; fire error LED ... if we get here something is wrong
    sbi PIND, PIND7                 ; invert output by writing 1 to input bit in output mode
    reti

关于assembly - 如何在AVR中产生占空比为20%的PWM脉冲?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30239610/

相关文章:

使用 PIC 18 PWM 控制直流电机

timer - Arduino PWM 衰落由 avra 引导

pic - PIC 上奇怪的 PWM 寄存器

c - 如何逐个字符地遍历字符串

linux - 在 ARM 上编写操作系统时,如何像在 x86 中一样实现基本的 I/O 功能?

c - 在 AVR 中使用 eeprom 函数的 C 语法错误

gcc - AT90USB162 (Minimus AVR) 上的 CDC 演示 COM 端口代码

c - 为什么 GCC 使用 Mov 而不是 Push In 函数调用?

c - 按位 - 位掩码操作是如何实现的?

c - AVR 9 位 Usart 不工作 (MPCM)