Zápisník experimentátora
Hierarchy: Časovač (timer)
In this article, we build on the previous article that described timer2. We will try to visualize the operation of the TCNT0 register, which is located in timer 0. Timer0 in Arduino handles the time calculation and therefore the operations on it also affect the millis and delay functions. We will show you a simple solution to deal with such a problem.
To create an animation we can use:
Everything is connected according to the following picture. The LEDs are connected to pins RX (0), TX (1), 2-7 and the picture also shows the GND connection on my LED board using two wire jumpers to the Arduino. The Arduino Pro Mini also has GND on the other side, so I could have used a single jumper, but then it would be badly photographed.
RX and TX are swapped because the bit of the 8-bit number will be displayed by writing directly to the PORTD register, and we need to have the pins aligned the same as the bits in the register. We will display the contents of the TCNT0 register, which is the register for timer0. In it, the value gradually increases up to the set value of the OCR0A register. This happens in the case of CTC mode. It should be true that the maximum value of TCNT0 = OCR0A. This is easy to check on the diodes, because if you write the value 63 (binary 0b00111111) to OCR0A, for example, the last two LEDs should not light up. If they light up, then you have programmed something wrong.
This program affects timer0 and therefore the millis and delay functions cannot be used in it.
I generated the basis of the program in my application. Because the Arduino clock is set to 16 MHz and we use an 8-bit timer, we cannot set it too low. The minimum is approximately 70 Hz. That's why I set it to 100 Hz.
In order to see that the program is working properly, I also let the LED on pine 13 flash in the program. The flashing takes place in the ISR interrupt handler (TIMER0_COMPA_vect
) and since the interrupt is triggered 100 times per second, I slowed it down using a variable divider
to 1 Hz.
The interrupt visualization is in the loop
function. We can't have it in an interrupt, because the TCNT0 register still has the same value when the interrupt is triggered. In the previous example, I delayed the entry at the register slightly at this point using the delay function. But we can't use it now, because I reprogrammed the timing of timer 0 and thus changed the time calculation for Arduino. For example, the delay
function is defined in the Arduino core as follows.
void delay(unsigned long ms)
{
uint32_t start = micros();
while (ms > 0) {
yield();
while ( ms > 0 && (micros() - start) >= 1000) {
ms--;
start += 1000;
}
}
}
Because in this case I only need some deceleration, I just need to use the nop
instruction in sufficient quantity. I used a cycle that uses this instruction in sufficient quantity to slow down the rendering for a few milliseconds to achieve the desired effect. The text in quotation marks must also be written with \n
at the end, because the assembler instructions are each written on a separate line and this will ensure us. When we have only one instruction, it is not as visible as if we used them more than once in the code.
for(long i=0;i<100000;i++)
__asm__("nop\n");
This created an interesting animation effect. It's a bit like old sci-fi movies, where spaceships, or any advanced technology, used to be displayed as a flashing group of lights.
When you look at the blinking, you will notice that the binary number does not go up to 255. If, for example, the value 31, 63 or 127 were in the OCR0A register, the LEDs from the upper bits would be even more visible. This is actually proof that it really counts correctly in CTC mode.
#define ledPin 13
int divider=0;
void setupTimer() {
noInterrupts();
TCCR0A = 0;
TCCR0B = 0;
TCNT0 = 0;
OCR0A = 155; // 100.16025641025641 Hz
TCCR0A |= (1 << WGM01);
TCCR0B |= 0;
TCCR0B |= (1 << CS02) | (0 << CS01) | (1 << CS00);
TIMSK0 |= (1 << OCIE0A);
interrupts();
}
void setup() {
pinMode(ledPin, OUTPUT);
for (int i = 0; i < 8; i++)
pinMode(i, OUTPUT);
setupTimer();
}
void loop() {
PORTD = TCNT0;
// delay replacement, because we changed timer0
for(long i=0;i<100000;i++)
__asm__("nop\n");
}
ISR(TIMER0_COMPA_vect) {
if(divider==0)
digitalWrite(ledPin, digitalRead(ledPin) ^ 1);
divider++;
divider%=100;
}
The source code is on the server GitHub.
31.05.2020