我正在尝试测量 atmega2560 执行矩阵乘法所需的时间。
为此,我在正常模式下使用 Timer0 并计算溢出中断的数量。
我设置了两种可能的配置,一种是每 1ms 获取一次中断,另一种是每 1us 获取一次中断。 问题是:当以毫秒为单位计时时,我得到 44ms,但是当以微秒为单位计时时,我得到 366us(我认为我应该至少得到 44,000 左右,反之亦然)。
这是timer0配置的代码,为了设置TCNT0寄存器,我遵循了此处指示的公式,我还检查了数据表:https://arcmicrocontrollers.files.wordpress.com/2022/07/imagen- 22.png
/*
*
* Contador con TIMER0
* Normal mode
* Interrupciones. Datasheet capitulo 16.
*
*/
#include "timer.h"
volatile uint16_t timer0_overflow_count = 0;
void timer0_init(uint8_t resolution) {
uint8_t prescaler = 0;
if (resolution == RESOLUTION_MS) {
prescaler = (1 << CS01) | (1 << CS00); // Prescaler 64
TCNT0 = 6;
}
else if (resolution == RESOLUTION_US) {
prescaler = (1 << CS01); // Prescaler 8
TCNT0 = 254;
}
// Habilitar la interrupción de overflow
TIMSK0 |= (1 << TOIE0);
// Iniciar el timer
TCCR0B = prescaler;
// Habilitar interrupciones globales
sei();
}
// Función para obtener el tiempo transcurrido
uint16_t timer0_getCount() {
return timer0_overflow_count;
}
// Rutina de interrupción para el desbordamiento del TIMER0
ISR(TIMER0_OVF_vect) {
timer0_overflow_count++;
}
这是我的主要程序
/*
*
* El tamaño máximo de memoria disponible para matrices en ram es
* 8 Kb
*
*/
#include <avr/io.h>
#include <stdlib.h>
#include <util/delay.h>
#include <uart.h>
#include <timer.h>
#define F_CPU 16000000
uint8_t const n = 32;
uint8_t* A, * B, * C;
// blink builtin led
void error() {
while (1) {
PORTB |= (1 << 7);
_delay_ms(20);
PORTB &= ~(1 << 7);
_delay_ms(200);
}
}
// perform matrix product
void multiplicar() {
for (uint8_t i = 0; i < n; i++) {
for (uint8_t j = 0; j < n; j++) {
for (uint8_t k = 0; k < n; k++) {
C[i * n + j] += A[i * n + k] * B[j * n + k];
}
}
}
}
// Validates operation result
void validar() {
for (uint16_t i = 0; i < n * n; i++) {
if (C[i] != n) {
error(); //bloqueante
}
}
}
int main() {
DDRB |= (1<<7); // Led
UART_Init();
A=(uint8_t*)malloc(n*n*sizeof(uint8_t));
B=(uint8_t*)malloc(n*n*sizeof(uint8_t));
C=(uint8_t*)malloc(n*n*sizeof(uint8_t));
// Check if there was enough memory
if (A == NULL || B==NULL || C == NULL){
error();
}
// Initialize matrices
for (int i = 0; i < n*n; i++)
{
A[i]=1;
B[i]=1;
C[i]=0;
}
uint8_t res= RESOLUTION_US;
timer0_init(res);
multiplicar();
uint16_t time = timer0_getCount();
validar();
// Print elapsed time
UART_PrintStr("Tiempo transcurrido: ");
UART_PrintNumber(time);
(res == RESOLUTION_MS) ? UART_PrintStr(" ms\n") : UART_PrintStr(" us\n");
while (1) {
}
return 0;
}
如果您通过在函数启动时将引脚驱动为高电平、在函数结束时将其驱动为低电平并在示波器上查看信号来测量算法的运行时间,将会更加可靠和准确。
如果你确实想在AVR上使用定时器来测量运行时间,你可以这样做,但最好避免使用中断或尽量减少中断的数量,因为每个中断都会占用一些CPU周期,影响您尝试进行的测量。因此,您想要做的是重置定时器的计数器,将预分频器设置为相当高的值以最小化开销,运行您的算法,然后最后您将记录发生的溢出中断数和当前计时器的计数。避免由于溢出而出现错误有点棘手,但您可以将两者一起使用来计算运行时间。
尝试在可能以 16 MHz 或更低频率运行的 8 位 AVR 上每微秒运行一次中断并不是一个好主意。请记住,8 位 AVR 一微秒最多只能执行 16 条指令,而您的简单 ISR 需要 8 条指令。
我在您的代码中看到的主要问题是,当您从毫秒更改为微秒时,您所做的唯一相关的事情是将预分频器更改为 8 倍。您对 TCNT0 的写入是无关紧要的,因为一旦计时器达到其顶部值和溢出,TCNT0 中的计数应该回到 0。您需要查阅 ATMega2560 数据表,看看定时器 0 的 TOP 值存储在哪个寄存器中,然后写入该寄存器而不是 TCNT0。
您可能还需要解决其他问题。我没有仔细查看数据表。