2017-02-15 33 views
0

我試圖在SimAVR運行下面的AVR程序:時鐘頻率設置不會改變仿真速度

#include <avr/io.h> 
#include <util/delay.h> 

int main() 
{ 
    DDRB |= _BV(DDB5); 

    for (;;) 
    { 
     PORTB ^= _BV(PB5); 
     _delay_ms(2000); 
    } 
} 

我和F_CPU=16000000編譯它。該SimAVR亞軍如下:

#include <stdlib.h> 
#include <stdio.h> 
#include <pthread.h> 

#include "sim_avr.h" 
#include "avr_ioport.h" 
#include "sim_elf.h" 

avr_t * avr = NULL; 

static void* avr_run_thread(void * ignore) 
{ 
    for (;;) { 
     avr_run(avr); 
    } 
    return NULL; 
} 

void led_changed_hook(struct avr_irq_t* irq, uint32_t value, void* param) 
{ 
    printf("led_changed_hook %d %d\n", irq->irq, value); 
} 

int main(int argc, char *argv[]) 
{ 
    elf_firmware_t f; 
    elf_read_firmware("image.elf", &f); 
    f.frequency = 16e6; 

    const char *mmcu = "atmega328p"; 
    avr = avr_make_mcu_by_name(mmcu); 
    if (!avr) { 
     fprintf(stderr, "%s: AVR '%s' not known\n", argv[0], mmcu); 
     exit(1); 
    } 
    avr_init(avr); 
    avr_load_firmware(avr, &f); 

    avr_irq_register_notify(
     avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('B'), 5), 
     led_changed_hook, 
     NULL); 

    pthread_t run; 
    pthread_create(&run, NULL, avr_run_thread, NULL); 

    for (;;) {} 
} 

的問題是,我從led_changed_hook輸出,它運行在〜4倍的速度看。而且,改變f.frequency似乎對模擬速度沒有任何影響。

如何確保SimAVR以正確的實時速度運行模擬?

+0

爲什麼要在CPU頻率上升時,以毫秒爲單位的延遲主要由更快的速度運行? – tofro

+0

我以爲'_delay_ms'宏擴展爲忙等待?例如,如果我用'F_CPU = 800000'對其進行編譯,然後將其上載並運行在運行頻率爲16MHz的真實芯片上,我確實發現閃爍速度是兩倍。 – Cactus

+0

@tofro:[此文檔頁面](http://www.nongnu.org/avr-libc/user-manual/group__util__delay.html)非常明確指出'_delay_ms'&c。正在使用忙等待編譯時計算的循環數。 – Cactus

回答

0

It turns out SimAVR doesn't support timing-accurate simulation of opcodes因此運行的_delay_ms完成的忙等待的仿真時間是完全無關的

  • 它需要多長時間的實際MCU
  • 模擬MCU的時鐘頻率

正確的解決方案是使用定時器中斷,然後在MCU上休眠。模擬器將正確模擬計時器計數器,並且睡眠將暫停模擬,直到計時器觸發。

#include <avr/interrupt.h> 
#include <avr/power.h> 
#include <avr/sleep.h> 

int main() 
{ 
    DDRB |= _BV(DDB5); 

    TCCR1A = 0; 
    TCCR1B = 0; 
    TCNT1 = 0; 
    TIMSK1 |= (1 << OCIE1A); 

    sei(); 

    /* Set TIMER1 to 0.5 Hz */ 
    TCCR1B |= (1 << WGM12); 
    OCR1A = 31248; 
    TCCR1B |= ((1 << CS12) | (1 << CS10)); 

    set_sleep_mode(SLEEP_MODE_IDLE); 
    sleep_enable(); 
    for (;;) 
    { 
     sleep_mode(); 
    } 
} 

ISR(TIMER1_COMPA_vect){ 
    PORTB ^= _BV(PB5); 
}